gdi32: Implement CreateScalableFontResource.
[wine.git] / dlls / gdi32 / freetype.c
blobd61605eab03e9c8f06bfd6f814a09bd57d106bd3
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 DWORD ntmFlags;
269 FT_Fixed font_version;
270 BOOL scalable;
271 BOOL vertical;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 WCHAR *FamilyName;
282 WCHAR *EnglishName;
283 struct list faces;
284 struct list *replacement;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 FONTSIGNATURE fs;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
385 GdiFont *font;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
416 System_Value,
417 OEMFont_Value,
418 FixedSys_Value,
419 NULL
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
448 times_new_roman,
449 liberation_serif,
450 bitstream_vera_serif,
451 NULL
454 static const WCHAR *default_fixed_list[] =
456 courier_new,
457 liberation_mono,
458 bitstream_vera_sans_mono,
459 NULL
462 static const WCHAR *default_sans_list[] =
464 arial,
465 liberation_sans,
466 bitstream_vera_sans,
467 NULL
470 typedef struct {
471 WCHAR *name;
472 INT charset;
473 } NameCs;
475 typedef struct tagFontSubst {
476 struct list entry;
477 NameCs from;
478 NameCs to;
479 } FontSubst;
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
501 struct font_mapping
503 struct list entry;
504 int refcount;
505 dev_t dev;
506 ino_t ino;
507 void *data;
508 size_t size;
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
516 0, 0, &freetype_cs,
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * Key Meaning
547 * FIXEDFON.FON FixedSys
548 * FONTS.FON System
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
562 * I have
563 * woafont=app850.fon
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
575 typedef struct {
576 DWORD version;
577 WORD ScriptList;
578 WORD FeatureList;
579 WORD LookupList;
580 } GSUB_Header;
582 typedef struct {
583 CHAR ScriptTag[4];
584 WORD Script;
585 } GSUB_ScriptRecord;
587 typedef struct {
588 WORD ScriptCount;
589 GSUB_ScriptRecord ScriptRecord[1];
590 } GSUB_ScriptList;
592 typedef struct {
593 CHAR LangSysTag[4];
594 WORD LangSys;
595 } GSUB_LangSysRecord;
597 typedef struct {
598 WORD DefaultLangSys;
599 WORD LangSysCount;
600 GSUB_LangSysRecord LangSysRecord[1];
601 } GSUB_Script;
603 typedef struct {
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
606 WORD FeatureCount;
607 WORD FeatureIndex[1];
608 } GSUB_LangSys;
610 typedef struct {
611 CHAR FeatureTag[4];
612 WORD Feature;
613 } GSUB_FeatureRecord;
615 typedef struct {
616 WORD FeatureCount;
617 GSUB_FeatureRecord FeatureRecord[1];
618 } GSUB_FeatureList;
620 typedef struct {
621 WORD FeatureParams; /* Reserved */
622 WORD LookupCount;
623 WORD LookupListIndex[1];
624 } GSUB_Feature;
626 typedef struct {
627 WORD LookupCount;
628 WORD Lookup[1];
629 } GSUB_LookupList;
631 typedef struct {
632 WORD LookupType;
633 WORD LookupFlag;
634 WORD SubTableCount;
635 WORD SubTable[1];
636 } GSUB_LookupTable;
638 typedef struct {
639 WORD CoverageFormat;
640 WORD GlyphCount;
641 WORD GlyphArray[1];
642 } GSUB_CoverageFormat1;
644 typedef struct {
645 WORD Start;
646 WORD End;
647 WORD StartCoverageIndex;
648 } GSUB_RangeRecord;
650 typedef struct {
651 WORD CoverageFormat;
652 WORD RangeCount;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
656 typedef struct {
657 WORD SubstFormat; /* = 1 */
658 WORD Coverage;
659 WORD DeltaGlyphID;
660 } GSUB_SingleSubstFormat1;
662 typedef struct {
663 WORD SubstFormat; /* = 2 */
664 WORD Coverage;
665 WORD GlyphCount;
666 WORD Substitute[1];
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
672 FSRef ref;
673 OSErr err;
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
680 if(err != noErr)
682 WARN("can't create cached data folder\n");
683 return NULL;
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
686 if(err != noErr)
688 WARN("can't create cached data path\n");
689 *cached_path = '\0';
690 return NULL;
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
695 *cached_path = '\0';
696 return NULL;
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
703 *cached_path = '\0';
704 return NULL;
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
710 *cached_path = '\0';
711 return NULL;
713 return cached_path;
716 /******************************************************************
717 * expand_mac_font
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
721 * find_cache_dir()).
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
729 FSRef ref;
730 SInt16 res_ref;
731 OSStatus s;
732 unsigned int idx;
733 const char *out_dir;
734 const char *filename;
735 int output_len;
736 struct {
737 char **array;
738 unsigned int size, max_size;
739 } ret;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
744 if(s != noErr)
746 WARN("failed to get ref\n");
747 return NULL;
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
751 if(s != noErr)
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
755 if(res_ref == -1)
757 TRACE("unable to open resource fork\n");
758 return NULL;
762 ret.size = 0;
763 ret.max_size = 10;
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
765 if(!ret.array)
767 CloseResFile(res_ref);
768 return NULL;
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
775 else filename++;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
780 UseResFile(res_ref);
781 idx = 1;
782 while(1)
784 FamRec *fam_rec;
785 unsigned short *num_faces_ptr, num_faces, face;
786 AsscEntry *assoc;
787 Handle fond;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
791 if(!fond) break;
792 TRACE("got fond resource %d\n", idx);
793 HLock(fond);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
798 num_faces++;
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
803 Handle sfnt;
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
806 char *output;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
810 if(size != 0)
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
813 continue;
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
818 if(!sfnt)
820 TRACE("can't get sfnt resource %04x\n", font_id);
821 continue;
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
825 if(output)
827 int fd;
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
834 if(fd != -1)
836 unsigned char *sfnt_data;
838 HLock(sfnt);
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
841 HUnlock(sfnt);
842 close(fd);
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.max_size *= 2;
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
851 else
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
859 HUnlock(fond);
860 ReleaseResource(fond);
861 idx++;
863 CloseResFile(res_ref);
865 return ret.array;
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
880 return f * 0x10000;
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
897 else
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
903 Family *family;
904 Face *face;
905 const char *file;
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
916 continue;
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
920 if (!face->file)
921 continue;
922 file = strrchr(face->file, '/');
923 if(!file)
924 file = face->file;
925 else
926 file++;
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
930 return face;
934 HeapFree(GetProcessHeap(), 0, file_nameA);
935 return NULL;
938 static Family *find_family_from_name(const WCHAR *name)
940 Family *family;
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
945 return family;
948 return NULL;
951 static Family *find_family_from_any_name(const WCHAR *name)
953 Family *family;
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
958 return family;
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
960 return family;
963 return NULL;
966 static void DumpSubstList(void)
968 FontSubst *psub;
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 else
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
979 return;
982 static LPWSTR strdupW(LPCWSTR p)
984 LPWSTR ret;
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
987 memcpy(ret, p, len);
988 return ret;
991 static LPSTR strdupA(LPCSTR p)
993 LPSTR ret;
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
996 memcpy(ret, p, len);
997 return ret;
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1001 INT from_charset)
1003 FontSubst *element;
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1010 return element;
1013 return NULL;
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1030 from_exist = NULL;
1033 if(!from_exist)
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1037 if(to_exist)
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1045 return TRUE;
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1051 return FALSE;
1054 static WCHAR *towstr(UINT cp, const char *str)
1056 int len;
1057 WCHAR *wstr;
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1062 return wstr;
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1069 nc->charset = -1;
1070 if(p && *(p+1)) {
1071 nc->charset = strtol(p+1, NULL, 10);
1072 *p = '\0';
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1079 FontSubst *psub;
1080 HKEY hkey;
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1082 LPSTR value;
1083 LPVOID data;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 dlen = datalen;
1097 vlen = valuelen;
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1113 } else {
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1117 dlen = datalen;
1118 vlen = valuelen;
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1122 RegCloseKey(hkey);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_SfntName name;
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1155 return TRUE;
1160 req->string = NULL;
1161 req->string_len = 0;
1162 return FALSE;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1167 WCHAR *ret = NULL;
1168 FT_SfntName name;
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1177 FT_UInt i;
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1186 ret[i] = 0;
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1190 return ret;
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1195 DWORD type, needed;
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1209 DWORD needed;
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1216 DWORD italic, bold;
1217 Face *face;
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1226 face->vertical = (family->FamilyName[0] == '@');
1228 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1230 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1231 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1232 face->FullName = fullName;
1234 else
1235 face->FullName = NULL;
1237 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1238 reg_load_dword(hkey_face, face_italic_value, &italic);
1239 reg_load_dword(hkey_face, face_bold_value, &bold);
1240 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1241 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1243 needed = sizeof(face->fs);
1244 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1251 else
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1265 face->ntmFlags = 0;
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1277 else
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1295 HKEY hkey_strike;
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1307 WCHAR *family_name;
1308 DWORD family_index = 0;
1309 Family *family;
1310 HKEY hkey_family;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1322 WCHAR *face_name;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 family->replacement = &family->faces;
1338 list_add_tail(&font_list, &family->entry);
1340 if(english_family)
1342 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1343 subst->from.name = strdupW(english_family);
1344 subst->from.charset = -1;
1345 subst->to.name = strdupW(family_name);
1346 subst->to.charset = -1;
1347 add_font_subst(&font_subst_list, subst, 0);
1350 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1351 NULL, NULL, NULL, NULL);
1353 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1354 size = max_face_key_len + 1;
1355 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1356 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1358 HKEY hkey_face;
1360 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1361 load_face(hkey_face, face_name, family);
1362 RegCloseKey(hkey_face);
1363 size = max_face_key_len + 1;
1365 HeapFree(GetProcessHeap(), 0, face_name);
1366 RegCloseKey(hkey_family);
1367 size = max_family_key_len + 1;
1370 HeapFree(GetProcessHeap(), 0, family_name);
1373 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1375 LONG ret;
1376 HKEY hkey_wine_fonts;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1380 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1381 if(ret != ERROR_SUCCESS)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1384 return ret;
1387 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1388 KEY_ALL_ACCESS, NULL, hkey, disposition);
1389 RegCloseKey(hkey_wine_fonts);
1390 return ret;
1393 static void add_face_to_cache(Face *face)
1395 HKEY hkey_font_cache, hkey_family, hkey_face;
1396 WCHAR *face_key_name;
1398 create_font_cache_key(&hkey_font_cache, NULL);
1400 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1401 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1402 if(face->family->EnglishName)
1403 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1404 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1406 if(face->scalable)
1407 face_key_name = face->StyleName;
1408 else
1410 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1411 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1412 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1414 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1415 &hkey_face, NULL);
1416 if(!face->scalable)
1417 HeapFree(GetProcessHeap(), 0, face_key_name);
1419 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1420 if (face->FullName)
1421 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1422 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1424 reg_save_dword(hkey_face, face_index_value, face->face_index);
1425 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1426 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1427 reg_save_dword(hkey_face, face_version_value, face->font_version);
1428 reg_save_dword(hkey_face, face_external_value, face->external);
1430 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1432 if(!face->scalable)
1434 reg_save_dword(hkey_face, face_height_value, face->size.height);
1435 reg_save_dword(hkey_face, face_width_value, face->size.width);
1436 reg_save_dword(hkey_face, face_size_value, face->size.size);
1437 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1438 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1439 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1441 RegCloseKey(hkey_face);
1442 RegCloseKey(hkey_family);
1443 RegCloseKey(hkey_font_cache);
1446 static inline int TestStyles(DWORD flags, DWORD styles)
1448 return (flags & styles) == styles;
1451 static inline int style_order(Face *face)
1453 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1454 return 3;
1455 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1456 return 2;
1457 if (TestStyles(face->ntmFlags, NTM_BOLD))
1458 return 1;
1459 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1460 return 0;
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face->family->FamilyName),
1464 debugstr_w(face->StyleName),
1465 face->ntmFlags);
1467 return 9999;
1470 static WCHAR *prepend_at(WCHAR *family)
1472 WCHAR *str;
1474 if (!family)
1475 return NULL;
1477 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1478 str[0] = '@';
1479 strcpyW(str + 1, family);
1480 HeapFree(GetProcessHeap(), 0, family);
1481 return str;
1484 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1486 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1487 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1489 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1490 if (!*name)
1492 *name = *english;
1493 *english = NULL;
1495 else if (!strcmpiW( *name, *english ))
1497 HeapFree( GetProcessHeap(), 0, *english );
1498 *english = NULL;
1501 if (vertical)
1503 *name = prepend_at( *name );
1504 *english = prepend_at( *english );
1508 /****************************************************************
1509 * NB This function stores the ptrs to the strings to save copying.
1510 * Don't free them after calling.
1512 static Family *create_family( WCHAR *name, WCHAR *english_name )
1514 Family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1515 family->FamilyName = name;
1516 family->EnglishName = english_name;
1517 list_init( &family->faces );
1518 family->replacement = &family->faces;
1520 return family;
1523 static Family *get_family( FT_Face ft_face, BOOL vertical )
1525 Family *family;
1526 WCHAR *name, *english_name;
1528 get_family_names( ft_face, &name, &english_name, vertical );
1530 family = find_family_from_name( name );
1532 if (!family)
1534 family = create_family( name, english_name );
1535 list_add_tail( &font_list, &family->entry );
1537 if (english_name)
1539 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1540 subst->from.name = strdupW( english_name );
1541 subst->from.charset = -1;
1542 subst->to.name = strdupW( name );
1543 subst->to.charset = -1;
1544 add_font_subst( &font_subst_list, subst, 0 );
1547 else
1549 HeapFree( GetProcessHeap(), 0, name );
1550 HeapFree( GetProcessHeap(), 0, english_name );
1553 return family;
1556 static inline FT_Fixed get_font_version( FT_Face ft_face )
1558 FT_Fixed version = 0;
1559 TT_Header *header;
1561 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1562 if (header) version = header->Font_Revision;
1564 return version;
1567 static inline DWORD get_ntm_flags( FT_Face ft_face )
1569 DWORD flags = 0;
1570 FT_ULong table_size = 0;
1572 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1573 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1574 if (flags == 0) flags = NTM_REGULAR;
1576 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1577 flags |= NTM_PS_OPENTYPE;
1579 return flags;
1582 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1584 int internal_leading = 0;
1585 FT_WinFNT_HeaderRec winfnt_header;
1587 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1588 internal_leading = winfnt_header.internal_leading;
1590 return internal_leading;
1593 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1595 TT_OS2 *os2;
1596 FT_UInt dummy;
1597 CHARSETINFO csi;
1598 FT_WinFNT_HeaderRec winfnt_header;
1599 int i;
1601 memset( fs, 0, sizeof(*fs) );
1603 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1604 if (os2)
1606 fs->fsUsb[0] = os2->ulUnicodeRange1;
1607 fs->fsUsb[1] = os2->ulUnicodeRange2;
1608 fs->fsUsb[2] = os2->ulUnicodeRange3;
1609 fs->fsUsb[3] = os2->ulUnicodeRange4;
1611 if (os2->version == 0)
1613 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1614 fs->fsCsb[0] = FS_LATIN1;
1615 else
1616 fs->fsCsb[0] = FS_SYMBOL;
1618 else
1620 fs->fsCsb[0] = os2->ulCodePageRange1;
1621 fs->fsCsb[1] = os2->ulCodePageRange2;
1624 else
1626 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1628 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1629 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1630 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1631 *fs = csi.fs;
1635 if (fs->fsCsb[0] == 0)
1637 /* let's see if we can find any interesting cmaps */
1638 for (i = 0; i < ft_face->num_charmaps; i++)
1640 switch (ft_face->charmaps[i]->encoding)
1642 case FT_ENCODING_UNICODE:
1643 case FT_ENCODING_APPLE_ROMAN:
1644 fs->fsCsb[0] |= FS_LATIN1;
1645 break;
1646 case FT_ENCODING_MS_SYMBOL:
1647 fs->fsCsb[0] |= FS_SYMBOL;
1648 break;
1649 default:
1650 break;
1656 static inline void free_face( Face *face )
1658 HeapFree( GetProcessHeap(), 0, face->file );
1659 HeapFree( GetProcessHeap(), 0, face->StyleName );
1660 HeapFree( GetProcessHeap(), 0, face->FullName );
1661 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1662 HeapFree( GetProcessHeap(), 0, face );
1665 static inline void free_family( Family *family )
1667 Face *face, *cursor2;
1669 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1671 list_remove( &face->entry );
1672 free_face( face );
1674 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1675 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1676 HeapFree( GetProcessHeap(), 0, family );
1679 #define ADDFONT_EXTERNAL_FONT 0x01
1680 #define ADDFONT_FORCE_BITMAP 0x02
1681 #define ADDFONT_ADD_TO_CACHE 0x04
1683 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1684 DWORD flags, BOOL vertical )
1686 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1687 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1689 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1690 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1691 if (file)
1693 face->file = strdupA( file );
1694 face->font_data_ptr = NULL;
1695 face->font_data_size = 0;
1697 else
1699 face->file = NULL;
1700 face->font_data_ptr = font_data_ptr;
1701 face->font_data_size = font_data_size;
1704 face->face_index = face_index;
1705 get_fontsig( ft_face, &face->fs );
1706 face->ntmFlags = get_ntm_flags( ft_face );
1707 face->font_version = get_font_version( ft_face );
1709 if (FT_IS_SCALABLE( ft_face ))
1711 memset( &face->size, 0, sizeof(face->size) );
1712 face->scalable = TRUE;
1714 else
1716 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1717 size->height, size->width, size->size >> 6,
1718 size->x_ppem >> 6, size->y_ppem >> 6);
1719 face->size.height = size->height;
1720 face->size.width = size->width;
1721 face->size.size = size->size;
1722 face->size.x_ppem = size->x_ppem;
1723 face->size.y_ppem = size->y_ppem;
1724 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1725 face->scalable = FALSE;
1728 face->vertical = vertical;
1729 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1730 face->family = NULL;
1731 face->cached_enum_data = NULL;
1733 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1734 face->fs.fsCsb[0], face->fs.fsCsb[1],
1735 face->fs.fsUsb[0], face->fs.fsUsb[1],
1736 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1738 return face;
1741 static inline BOOL faces_equal( Face *f1, Face *f2 )
1743 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1744 if (f1->scalable) return TRUE;
1745 if (f2->size.y_ppem != f2->size.y_ppem) return FALSE;
1746 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1749 static BOOL insert_face_in_family_list( Face *face, Family *family )
1751 Face *cursor;
1753 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1755 if (faces_equal( face, cursor ))
1757 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1758 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1759 cursor->font_version, face->font_version);
1761 if (face->font_version <= cursor->font_version)
1763 TRACE("Original font is newer so skipping this one\n");
1764 return FALSE;
1766 else
1768 TRACE("Replacing original with this one\n");
1769 list_add_before( &cursor->entry, &face->entry );
1770 face->family = family;
1771 list_remove( &cursor->entry);
1772 free_face( cursor );
1773 return TRUE;
1777 if (style_order( face ) < style_order( cursor )) break;
1780 list_add_before( &cursor->entry, &face->entry );
1781 face->family = family;
1782 return TRUE;
1785 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1786 FT_Long face_index, DWORD flags, BOOL vertical)
1788 Face *face;
1789 Family *family;
1791 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1792 family = get_family( ft_face, vertical );
1793 if (!insert_face_in_family_list( face, family ))
1795 free_face( face );
1796 return;
1799 if (flags & ADDFONT_ADD_TO_CACHE)
1800 add_face_to_cache( face );
1802 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1803 debugstr_w(face->StyleName));
1806 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1807 FT_Long face_index, BOOL allow_bitmap )
1809 FT_Error err;
1810 TT_OS2 *pOS2;
1811 FT_Face ft_face;
1813 if (file)
1815 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1816 err = pFT_New_Face(library, file, face_index, &ft_face);
1818 else
1820 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1821 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1824 if (err != 0)
1826 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1827 return NULL;
1830 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1831 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1833 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1834 goto fail;
1837 if (!FT_IS_SFNT( ft_face ))
1839 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1841 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1842 goto fail;
1845 else
1847 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1848 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1849 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1851 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1852 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1853 goto fail;
1856 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1857 we don't want to load these. */
1858 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1860 FT_ULong len = 0;
1862 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1864 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1865 goto fail;
1870 if (!ft_face->family_name || !ft_face->style_name)
1872 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1873 goto fail;
1876 return ft_face;
1877 fail:
1878 pFT_Done_Face( ft_face );
1879 return NULL;
1882 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1884 FT_Face ft_face;
1885 FT_Long face_index = 0, num_faces;
1886 INT ret = 0;
1888 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1889 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1891 #ifdef HAVE_CARBON_CARBON_H
1892 if(file)
1894 char **mac_list = expand_mac_font(file);
1895 if(mac_list)
1897 BOOL had_one = FALSE;
1898 char **cursor;
1899 for(cursor = mac_list; *cursor; cursor++)
1901 had_one = TRUE;
1902 AddFontToList(*cursor, NULL, 0, flags);
1903 HeapFree(GetProcessHeap(), 0, *cursor);
1905 HeapFree(GetProcessHeap(), 0, mac_list);
1906 if(had_one)
1907 return 1;
1910 #endif /* HAVE_CARBON_CARBON_H */
1912 do {
1913 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1914 if (!ft_face) return 0;
1916 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1918 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1919 pFT_Done_Face(ft_face);
1920 return 0;
1923 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1924 ++ret;
1926 if (FT_HAS_VERTICAL(ft_face))
1928 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1929 ++ret;
1932 num_faces = ft_face->num_faces;
1933 pFT_Done_Face(ft_face);
1934 } while(num_faces > ++face_index);
1935 return ret;
1938 static void DumpFontList(void)
1940 Family *family;
1941 Face *face;
1942 struct list *family_elem_ptr, *face_elem_ptr;
1944 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1945 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1946 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1947 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1948 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1949 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1950 if(!face->scalable)
1951 TRACE(" %d", face->size.height);
1952 TRACE("\n");
1955 return;
1958 /***********************************************************
1959 * The replacement list is a way to map an entire font
1960 * family onto another family. For example adding
1962 * [HKCU\Software\Wine\Fonts\Replacements]
1963 * "Wingdings"="Winedings"
1965 * would enumerate the Winedings font both as Winedings and
1966 * Wingdings. However if a real Wingdings font is present the
1967 * replacement does not take place.
1970 static void LoadReplaceList(void)
1972 HKEY hkey;
1973 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1974 LPWSTR value;
1975 LPVOID data;
1976 CHAR familyA[400];
1978 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1979 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1981 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1982 &valuelen, &datalen, NULL, NULL);
1984 valuelen++; /* returned value doesn't include room for '\0' */
1985 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1986 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1988 dlen = datalen;
1989 vlen = valuelen;
1990 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1991 &dlen) == ERROR_SUCCESS) {
1992 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1993 /* "NewName"="Oldname" */
1994 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1996 if(!find_family_from_any_name(value))
1998 Family * const family = find_family_from_any_name(data);
1999 if (family != NULL)
2001 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2002 if (new_family != NULL)
2004 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2005 new_family->FamilyName = strdupW(value);
2006 new_family->EnglishName = NULL;
2007 list_init(&new_family->faces);
2008 new_family->replacement = &family->faces;
2009 list_add_tail(&font_list, &new_family->entry);
2012 else
2014 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2017 else
2019 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2021 /* reset dlen and vlen */
2022 dlen = datalen;
2023 vlen = valuelen;
2025 HeapFree(GetProcessHeap(), 0, data);
2026 HeapFree(GetProcessHeap(), 0, value);
2027 RegCloseKey(hkey);
2031 static const WCHAR *font_links_list[] =
2033 Lucida_Sans_Unicode,
2034 Microsoft_Sans_Serif,
2035 Tahoma
2038 static const struct font_links_defaults_list
2040 /* Keyed off substitution for "MS Shell Dlg" */
2041 const WCHAR *shelldlg;
2042 /* Maximum of four substitutes, plus terminating NULL pointer */
2043 const WCHAR *substitutes[5];
2044 } font_links_defaults_list[] =
2046 /* Non East-Asian */
2047 { Tahoma, /* FIXME unverified ordering */
2048 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2050 /* Below lists are courtesy of
2051 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2053 /* Japanese */
2054 { MS_UI_Gothic,
2055 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2057 /* Chinese Simplified */
2058 { SimSun,
2059 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2061 /* Korean */
2062 { Gulim,
2063 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2065 /* Chinese Traditional */
2066 { PMingLiU,
2067 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2072 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2074 SYSTEM_LINKS *font_link;
2076 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2078 if(!strcmpiW(font_link->font_name, name))
2079 return font_link;
2082 return NULL;
2085 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2087 const WCHAR *value;
2088 int i;
2089 FontSubst *psub;
2090 Family *family;
2091 Face *face;
2092 const char *file;
2093 WCHAR *fileW;
2095 if (values)
2097 SYSTEM_LINKS *font_link;
2099 psub = get_font_subst(&font_subst_list, name, -1);
2100 /* Don't store fonts that are only substitutes for other fonts */
2101 if(psub)
2103 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2104 return;
2107 font_link = find_font_link(name);
2108 if (font_link == NULL)
2110 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2111 font_link->font_name = strdupW(name);
2112 list_init(&font_link->links);
2113 list_add_tail(&system_links, &font_link->entry);
2116 memset(&font_link->fs, 0, sizeof font_link->fs);
2117 for (i = 0; values[i] != NULL; i++)
2119 const struct list *face_list;
2120 CHILD_FONT *child_font;
2122 value = values[i];
2123 if (!strcmpiW(name,value))
2124 continue;
2125 psub = get_font_subst(&font_subst_list, value, -1);
2126 if(psub)
2127 value = psub->to.name;
2128 family = find_family_from_name(value);
2129 if (!family)
2130 continue;
2131 file = NULL;
2132 /* Use first extant filename for this Family */
2133 face_list = get_face_list_from_family(family);
2134 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2136 if (!face->file)
2137 continue;
2138 file = strrchr(face->file, '/');
2139 if (!file)
2140 file = face->file;
2141 else
2142 file++;
2143 break;
2145 if (!file)
2146 continue;
2147 fileW = towstr(CP_UNIXCP, file);
2149 face = find_face_from_filename(fileW, value);
2150 if(!face)
2152 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2153 continue;
2156 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2157 child_font->face = face;
2158 child_font->font = NULL;
2159 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2160 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2161 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2162 list_add_tail(&font_link->links, &child_font->entry);
2164 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2165 HeapFree(GetProcessHeap(), 0, fileW);
2171 /*************************************************************
2172 * init_system_links
2174 static BOOL init_system_links(void)
2176 HKEY hkey;
2177 BOOL ret = FALSE;
2178 DWORD type, max_val, max_data, val_len, data_len, index;
2179 WCHAR *value, *data;
2180 WCHAR *entry, *next;
2181 SYSTEM_LINKS *font_link, *system_font_link;
2182 CHILD_FONT *child_font;
2183 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2184 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2185 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2186 Face *face;
2187 FontSubst *psub;
2188 UINT i, j;
2190 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2192 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2193 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2194 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2195 val_len = max_val + 1;
2196 data_len = max_data;
2197 index = 0;
2198 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2200 psub = get_font_subst(&font_subst_list, value, -1);
2201 /* Don't store fonts that are only substitutes for other fonts */
2202 if(psub)
2204 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2205 goto next;
2207 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2208 font_link->font_name = strdupW(value);
2209 memset(&font_link->fs, 0, sizeof font_link->fs);
2210 list_init(&font_link->links);
2211 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2213 WCHAR *face_name;
2214 CHILD_FONT *child_font;
2216 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2218 next = entry + strlenW(entry) + 1;
2220 face_name = strchrW(entry, ',');
2221 if(face_name)
2223 *face_name++ = 0;
2224 while(isspaceW(*face_name))
2225 face_name++;
2227 psub = get_font_subst(&font_subst_list, face_name, -1);
2228 if(psub)
2229 face_name = psub->to.name;
2231 face = find_face_from_filename(entry, face_name);
2232 if(!face)
2234 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2235 continue;
2238 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2239 child_font->face = face;
2240 child_font->font = NULL;
2241 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2242 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2243 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2244 list_add_tail(&font_link->links, &child_font->entry);
2246 list_add_tail(&system_links, &font_link->entry);
2247 next:
2248 val_len = max_val + 1;
2249 data_len = max_data;
2252 HeapFree(GetProcessHeap(), 0, value);
2253 HeapFree(GetProcessHeap(), 0, data);
2254 RegCloseKey(hkey);
2258 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2259 if (!psub) {
2260 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2261 goto skip_internal;
2264 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2266 const FontSubst *psub2;
2267 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2269 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2271 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2272 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2274 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2275 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2277 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2279 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2283 skip_internal:
2285 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2286 that Tahoma has */
2288 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2289 system_font_link->font_name = strdupW(System);
2290 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2291 list_init(&system_font_link->links);
2293 face = find_face_from_filename(tahoma_ttf, Tahoma);
2294 if(face)
2296 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2297 child_font->face = face;
2298 child_font->font = NULL;
2299 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2300 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2301 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2302 list_add_tail(&system_font_link->links, &child_font->entry);
2304 font_link = find_font_link(Tahoma);
2305 if (font_link != NULL)
2307 CHILD_FONT *font_link_entry;
2308 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2310 CHILD_FONT *new_child;
2311 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2312 new_child->face = font_link_entry->face;
2313 new_child->font = NULL;
2314 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2315 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2316 list_add_tail(&system_font_link->links, &new_child->entry);
2319 list_add_tail(&system_links, &system_font_link->entry);
2320 return ret;
2323 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2325 DIR *dir;
2326 struct dirent *dent;
2327 char path[MAX_PATH];
2329 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2331 dir = opendir(dirname);
2332 if(!dir) {
2333 WARN("Can't open directory %s\n", debugstr_a(dirname));
2334 return FALSE;
2336 while((dent = readdir(dir)) != NULL) {
2337 struct stat statbuf;
2339 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2340 continue;
2342 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2344 sprintf(path, "%s/%s", dirname, dent->d_name);
2346 if(stat(path, &statbuf) == -1)
2348 WARN("Can't stat %s\n", debugstr_a(path));
2349 continue;
2351 if(S_ISDIR(statbuf.st_mode))
2352 ReadFontDir(path, external_fonts);
2353 else
2355 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2356 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2357 AddFontToList(path, NULL, 0, addfont_flags);
2360 closedir(dir);
2361 return TRUE;
2364 static void load_fontconfig_fonts(void)
2366 #ifdef SONAME_LIBFONTCONFIG
2367 void *fc_handle = NULL;
2368 FcConfig *config;
2369 FcPattern *pat;
2370 FcObjectSet *os;
2371 FcFontSet *fontset;
2372 int i, len;
2373 char *file;
2374 const char *ext;
2376 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2377 if(!fc_handle) {
2378 TRACE("Wine cannot find the fontconfig library (%s).\n",
2379 SONAME_LIBFONTCONFIG);
2380 return;
2382 #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;}
2383 LOAD_FUNCPTR(FcConfigGetCurrent);
2384 LOAD_FUNCPTR(FcFontList);
2385 LOAD_FUNCPTR(FcFontSetDestroy);
2386 LOAD_FUNCPTR(FcInit);
2387 LOAD_FUNCPTR(FcObjectSetAdd);
2388 LOAD_FUNCPTR(FcObjectSetCreate);
2389 LOAD_FUNCPTR(FcObjectSetDestroy);
2390 LOAD_FUNCPTR(FcPatternCreate);
2391 LOAD_FUNCPTR(FcPatternDestroy);
2392 LOAD_FUNCPTR(FcPatternGetBool);
2393 LOAD_FUNCPTR(FcPatternGetString);
2394 #undef LOAD_FUNCPTR
2396 if(!pFcInit()) return;
2398 config = pFcConfigGetCurrent();
2399 pat = pFcPatternCreate();
2400 os = pFcObjectSetCreate();
2401 pFcObjectSetAdd(os, FC_FILE);
2402 pFcObjectSetAdd(os, FC_SCALABLE);
2403 fontset = pFcFontList(config, pat, os);
2404 if(!fontset) return;
2405 for(i = 0; i < fontset->nfont; i++) {
2406 FcBool scalable;
2408 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2409 continue;
2410 TRACE("fontconfig: %s\n", file);
2412 /* We're just interested in OT/TT fonts for now, so this hack just
2413 picks up the scalable fonts without extensions .pf[ab] to save time
2414 loading every other font */
2416 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2418 TRACE("not scalable\n");
2419 continue;
2422 len = strlen( file );
2423 if(len < 4) continue;
2424 ext = &file[ len - 3 ];
2425 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2426 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2428 pFcFontSetDestroy(fontset);
2429 pFcObjectSetDestroy(os);
2430 pFcPatternDestroy(pat);
2431 sym_not_found:
2432 #endif
2433 return;
2436 static BOOL load_font_from_data_dir(LPCWSTR file)
2438 BOOL ret = FALSE;
2439 const char *data_dir = wine_get_data_dir();
2441 if (!data_dir) data_dir = wine_get_build_dir();
2443 if (data_dir)
2445 INT len;
2446 char *unix_name;
2448 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2450 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2452 strcpy(unix_name, data_dir);
2453 strcat(unix_name, "/fonts/");
2455 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2457 EnterCriticalSection( &freetype_cs );
2458 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2459 LeaveCriticalSection( &freetype_cs );
2460 HeapFree(GetProcessHeap(), 0, unix_name);
2462 return ret;
2465 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2467 static const WCHAR slashW[] = {'\\','\0'};
2468 BOOL ret = FALSE;
2469 WCHAR windowsdir[MAX_PATH];
2470 char *unixname;
2472 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2473 strcatW(windowsdir, fontsW);
2474 strcatW(windowsdir, slashW);
2475 strcatW(windowsdir, file);
2476 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2477 EnterCriticalSection( &freetype_cs );
2478 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2479 LeaveCriticalSection( &freetype_cs );
2480 HeapFree(GetProcessHeap(), 0, unixname);
2482 return ret;
2485 static void load_system_fonts(void)
2487 HKEY hkey;
2488 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2489 const WCHAR * const *value;
2490 DWORD dlen, type;
2491 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2492 char *unixname;
2494 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2495 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2496 strcatW(windowsdir, fontsW);
2497 for(value = SystemFontValues; *value; value++) {
2498 dlen = sizeof(data);
2499 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2500 type == REG_SZ) {
2501 BOOL added = FALSE;
2503 sprintfW(pathW, fmtW, windowsdir, data);
2504 if((unixname = wine_get_unix_file_name(pathW))) {
2505 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2506 HeapFree(GetProcessHeap(), 0, unixname);
2508 if (!added)
2509 load_font_from_data_dir(data);
2512 RegCloseKey(hkey);
2516 /*************************************************************
2518 * This adds registry entries for any externally loaded fonts
2519 * (fonts from fontconfig or FontDirs). It also deletes entries
2520 * of no longer existing fonts.
2523 static void update_reg_entries(void)
2525 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2526 LPWSTR valueW;
2527 DWORD len, len_fam;
2528 Family *family;
2529 Face *face;
2530 struct list *family_elem_ptr, *face_elem_ptr;
2531 WCHAR *file;
2532 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2533 static const WCHAR spaceW[] = {' ', '\0'};
2534 char *path;
2536 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2537 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2538 ERR("Can't create Windows font reg key\n");
2539 goto end;
2542 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2543 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2544 ERR("Can't create Windows font reg key\n");
2545 goto end;
2548 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2549 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2550 ERR("Can't create external font reg key\n");
2551 goto end;
2554 /* enumerate the fonts and add external ones to the two keys */
2556 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2557 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2558 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2559 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2560 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2561 if(!face->external) continue;
2562 len = len_fam;
2563 if (!(face->ntmFlags & NTM_REGULAR))
2564 len = len_fam + strlenW(face->StyleName) + 1;
2565 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2566 strcpyW(valueW, family->FamilyName);
2567 if(len != len_fam) {
2568 strcatW(valueW, spaceW);
2569 strcatW(valueW, face->StyleName);
2571 strcatW(valueW, TrueType);
2573 file = wine_get_dos_file_name(face->file);
2574 if(file)
2575 len = strlenW(file) + 1;
2576 else
2578 if((path = strrchr(face->file, '/')) == NULL)
2579 path = face->file;
2580 else
2581 path++;
2582 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2584 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2585 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2587 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2588 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2589 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2591 HeapFree(GetProcessHeap(), 0, file);
2592 HeapFree(GetProcessHeap(), 0, valueW);
2595 end:
2596 if(external_key) RegCloseKey(external_key);
2597 if(win9x_key) RegCloseKey(win9x_key);
2598 if(winnt_key) RegCloseKey(winnt_key);
2599 return;
2602 static void delete_external_font_keys(void)
2604 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2605 DWORD dlen, vlen, datalen, valuelen, i, type;
2606 LPWSTR valueW;
2607 LPVOID data;
2609 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2610 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2611 ERR("Can't create Windows font reg key\n");
2612 goto end;
2615 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2616 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2617 ERR("Can't create Windows font reg key\n");
2618 goto end;
2621 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2622 ERR("Can't create external font reg key\n");
2623 goto end;
2626 /* Delete all external fonts added last time */
2628 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2629 &valuelen, &datalen, NULL, NULL);
2630 valuelen++; /* returned value doesn't include room for '\0' */
2631 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2632 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2634 dlen = datalen * sizeof(WCHAR);
2635 vlen = valuelen;
2636 i = 0;
2637 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2638 &dlen) == ERROR_SUCCESS) {
2640 RegDeleteValueW(winnt_key, valueW);
2641 RegDeleteValueW(win9x_key, valueW);
2642 /* reset dlen and vlen */
2643 dlen = datalen;
2644 vlen = valuelen;
2646 HeapFree(GetProcessHeap(), 0, data);
2647 HeapFree(GetProcessHeap(), 0, valueW);
2649 /* Delete the old external fonts key */
2650 RegCloseKey(external_key);
2651 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2653 end:
2654 if(win9x_key) RegCloseKey(win9x_key);
2655 if(winnt_key) RegCloseKey(winnt_key);
2658 /*************************************************************
2659 * WineEngAddFontResourceEx
2662 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2664 INT ret = 0;
2666 GDI_CheckNotLock();
2668 if (ft_handle) /* do it only if we have freetype up and running */
2670 char *unixname;
2672 if(flags)
2673 FIXME("Ignoring flags %x\n", flags);
2675 if((unixname = wine_get_unix_file_name(file)))
2677 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2679 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2680 EnterCriticalSection( &freetype_cs );
2681 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2682 LeaveCriticalSection( &freetype_cs );
2683 HeapFree(GetProcessHeap(), 0, unixname);
2685 if (!ret && !strchrW(file, '\\')) {
2686 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2687 ret = load_font_from_winfonts_dir(file);
2688 if (!ret) {
2689 /* Try in datadir/fonts (or builddir/fonts),
2690 * needed for Magic the Gathering Online
2692 ret = load_font_from_data_dir(file);
2696 return ret;
2699 /*************************************************************
2700 * WineEngAddFontMemResourceEx
2703 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2705 GDI_CheckNotLock();
2707 if (ft_handle) /* do it only if we have freetype up and running */
2709 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2711 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2712 memcpy(pFontCopy, pbFont, cbFont);
2714 EnterCriticalSection( &freetype_cs );
2715 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2716 LeaveCriticalSection( &freetype_cs );
2718 if (*pcFonts == 0)
2720 TRACE("AddFontToList failed\n");
2721 HeapFree(GetProcessHeap(), 0, pFontCopy);
2722 return 0;
2724 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2725 * For now return something unique but quite random
2727 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2728 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2731 *pcFonts = 0;
2732 return 0;
2735 /*************************************************************
2736 * WineEngRemoveFontResourceEx
2739 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2741 GDI_CheckNotLock();
2742 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2743 return TRUE;
2746 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2748 WCHAR *fullname;
2749 char *unix_name;
2750 int file_len;
2752 if (!font_file) return NULL;
2754 file_len = strlenW( font_file );
2756 if (font_path && font_path[0])
2758 int path_len = strlenW( font_path );
2759 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2760 if (!fullname) return NULL;
2761 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2762 fullname[path_len] = '\\';
2763 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2765 else
2767 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2768 if (!len) return NULL;
2769 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2770 if (!fullname) return NULL;
2771 GetFullPathNameW( font_file, len, fullname, NULL );
2774 unix_name = wine_get_unix_file_name( fullname );
2775 HeapFree( GetProcessHeap(), 0, fullname );
2776 return unix_name;
2779 #include <pshpack1.h>
2780 struct fontdir
2782 WORD num_of_resources;
2783 WORD res_id;
2784 WORD dfVersion;
2785 DWORD dfSize;
2786 CHAR dfCopyright[60];
2787 WORD dfType;
2788 WORD dfPoints;
2789 WORD dfVertRes;
2790 WORD dfHorizRes;
2791 WORD dfAscent;
2792 WORD dfInternalLeading;
2793 WORD dfExternalLeading;
2794 BYTE dfItalic;
2795 BYTE dfUnderline;
2796 BYTE dfStrikeOut;
2797 WORD dfWeight;
2798 BYTE dfCharSet;
2799 WORD dfPixWidth;
2800 WORD dfPixHeight;
2801 BYTE dfPitchAndFamily;
2802 WORD dfAvgWidth;
2803 WORD dfMaxWidth;
2804 BYTE dfFirstChar;
2805 BYTE dfLastChar;
2806 BYTE dfDefaultChar;
2807 BYTE dfBreakChar;
2808 WORD dfWidthBytes;
2809 DWORD dfDevice;
2810 DWORD dfFace;
2811 DWORD dfReserved;
2812 CHAR szFaceName[LF_FACESIZE];
2815 #include <poppack.h>
2817 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2818 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2820 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2822 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2823 Face *face;
2824 Family *family;
2825 WCHAR *name, *english_name;
2826 ENUMLOGFONTEXW elf;
2827 NEWTEXTMETRICEXW ntm;
2828 DWORD type;
2830 if (!ft_face) return FALSE;
2831 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2832 get_family_names( ft_face, &name, &english_name, FALSE );
2833 family = create_family( name, english_name );
2834 insert_face_in_family_list( face, family );
2835 pFT_Done_Face( ft_face );
2837 GetEnumStructs( face, &elf, &ntm, &type );
2838 free_family( family );
2840 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2842 memset( fd, 0, sizeof(*fd) );
2844 fd->num_of_resources = 1;
2845 fd->res_id = 0;
2846 fd->dfVersion = 0x200;
2847 fd->dfSize = sizeof(*fd);
2848 strcpy( fd->dfCopyright, "Wine fontdir" );
2849 fd->dfType = 0x4003; /* 0x0080 set if private */
2850 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2851 fd->dfVertRes = 72;
2852 fd->dfHorizRes = 72;
2853 fd->dfAscent = ntm.ntmTm.tmAscent;
2854 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2855 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2856 fd->dfItalic = ntm.ntmTm.tmItalic;
2857 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2858 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2859 fd->dfWeight = ntm.ntmTm.tmWeight;
2860 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2861 fd->dfPixWidth = 0;
2862 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2863 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2864 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2865 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2866 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2867 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2868 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2869 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2870 fd->dfWidthBytes = 0;
2871 fd->dfDevice = 0;
2872 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2873 fd->dfReserved = 0;
2874 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2876 return TRUE;
2879 #define NE_FFLAGS_LIBMODULE 0x8000
2880 #define NE_OSFLAGS_WINDOWS 0x02
2882 static const char dos_string[0x40] = "This is a TrueType resource file";
2883 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2885 #include <pshpack2.h>
2887 struct ne_typeinfo
2889 WORD type_id;
2890 WORD count;
2891 DWORD res;
2894 struct ne_nameinfo
2896 WORD off;
2897 WORD len;
2898 WORD flags;
2899 WORD id;
2900 DWORD res;
2903 struct rsrc_tab
2905 WORD align;
2906 struct ne_typeinfo fontdir_type;
2907 struct ne_nameinfo fontdir_name;
2908 struct ne_typeinfo scalable_type;
2909 struct ne_nameinfo scalable_name;
2910 WORD end_of_rsrc;
2911 BYTE fontdir_res_name[8];
2914 #include <poppack.h>
2916 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
2918 BOOL ret = FALSE;
2919 HANDLE file;
2920 DWORD size, written;
2921 BYTE *ptr, *start;
2922 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
2923 char *font_fileA, *last_part, *ext;
2924 IMAGE_DOS_HEADER dos;
2925 IMAGE_OS2_HEADER ne =
2927 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
2928 0, 0, 0, 0, 0, 0,
2929 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
2930 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
2932 struct rsrc_tab rsrc_tab =
2935 { 0x8007, 1, 0 },
2936 { 0, 0, 0x0c50, 0x2c, 0 },
2937 { 0x80cc, 1, 0 },
2938 { 0, 0, 0x0c50, 0x8001, 0 },
2940 { 7,'F','O','N','T','D','I','R'}
2943 memset( &dos, 0, sizeof(dos) );
2944 dos.e_magic = IMAGE_DOS_SIGNATURE;
2945 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
2947 /* import name is last part\0, resident name is last part without extension
2948 non-resident name is "FONTRES:" + lfFaceName */
2950 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
2951 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
2952 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
2954 last_part = strrchr( font_fileA, '\\' );
2955 if (last_part) last_part++;
2956 else last_part = font_fileA;
2957 import_name_len = strlen( last_part ) + 1;
2959 ext = strchr( last_part, '.' );
2960 if (ext) res_name_len = ext - last_part;
2961 else res_name_len = import_name_len - 1;
2963 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
2965 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
2966 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
2967 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
2968 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
2969 ne.ne_cbenttab = 2;
2970 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
2972 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
2973 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
2974 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
2975 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
2977 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
2978 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2980 if (!ptr)
2982 HeapFree( GetProcessHeap(), 0, font_fileA );
2983 return FALSE;
2986 memcpy( ptr, &dos, sizeof(dos) );
2987 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
2988 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
2990 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
2991 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
2993 ptr = start + dos.e_lfanew + ne.ne_restab;
2994 *ptr++ = res_name_len;
2995 memcpy( ptr, last_part, res_name_len );
2997 ptr = start + dos.e_lfanew + ne.ne_imptab;
2998 *ptr++ = import_name_len;
2999 memcpy( ptr, last_part, import_name_len );
3001 ptr = start + ne.ne_nrestab;
3002 *ptr++ = non_res_name_len;
3003 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3004 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3006 ptr = start + (rsrc_tab.scalable_name.off << 4);
3007 memcpy( ptr, font_fileA, font_file_len );
3009 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3010 memcpy( ptr, fontdir, fontdir->dfSize );
3012 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3013 if (file != INVALID_HANDLE_VALUE)
3015 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3016 ret = TRUE;
3017 CloseHandle( file );
3020 HeapFree( GetProcessHeap(), 0, start );
3021 HeapFree( GetProcessHeap(), 0, font_fileA );
3023 return ret;
3026 /*************************************************************
3027 * WineEngCreateScalableFontResource
3030 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3031 LPCWSTR font_file, LPCWSTR font_path )
3033 char *unix_name = get_ttf_file_name( font_file, font_path );
3034 struct fontdir fontdir;
3035 BOOL ret = FALSE;
3037 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3038 SetLastError( ERROR_INVALID_PARAMETER );
3039 else
3041 if (hidden) fontdir.dfType |= 0x80;
3042 ret = create_fot( resource, font_file, &fontdir );
3045 HeapFree( GetProcessHeap(), 0, unix_name );
3046 return ret;
3049 static const struct nls_update_font_list
3051 UINT ansi_cp, oem_cp;
3052 const char *oem, *fixed, *system;
3053 const char *courier, *serif, *small, *sserif;
3054 /* these are for font substitutes */
3055 const char *shelldlg, *tmsrmn;
3056 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3057 *helv_0, *tmsrmn_0;
3058 const struct subst
3060 const char *from, *to;
3061 } arial_0, courier_new_0, times_new_roman_0;
3062 } nls_update_font_list[] =
3064 /* Latin 1 (United States) */
3065 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3066 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3067 "Tahoma","Times New Roman",
3068 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3069 { 0 }, { 0 }, { 0 }
3071 /* Latin 1 (Multilingual) */
3072 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3073 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3074 "Tahoma","Times New Roman", /* FIXME unverified */
3075 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3076 { 0 }, { 0 }, { 0 }
3078 /* Eastern Europe */
3079 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3080 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
3081 "Tahoma","Times New Roman", /* FIXME unverified */
3082 "Fixedsys,238", "System,238",
3083 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3084 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3085 { "Arial CE,0", "Arial,238" },
3086 { "Courier New CE,0", "Courier New,238" },
3087 { "Times New Roman CE,0", "Times New Roman,238" }
3089 /* Cyrillic */
3090 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3091 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
3092 "Tahoma","Times New Roman", /* FIXME unverified */
3093 "Fixedsys,204", "System,204",
3094 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3095 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3096 { "Arial Cyr,0", "Arial,204" },
3097 { "Courier New Cyr,0", "Courier New,204" },
3098 { "Times New Roman Cyr,0", "Times New Roman,204" }
3100 /* Greek */
3101 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3102 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
3103 "Tahoma","Times New Roman", /* FIXME unverified */
3104 "Fixedsys,161", "System,161",
3105 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3106 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3107 { "Arial Greek,0", "Arial,161" },
3108 { "Courier New Greek,0", "Courier New,161" },
3109 { "Times New Roman Greek,0", "Times New Roman,161" }
3111 /* Turkish */
3112 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3113 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
3114 "Tahoma","Times New Roman", /* FIXME unverified */
3115 "Fixedsys,162", "System,162",
3116 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3117 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3118 { "Arial Tur,0", "Arial,162" },
3119 { "Courier New Tur,0", "Courier New,162" },
3120 { "Times New Roman Tur,0", "Times New Roman,162" }
3122 /* Hebrew */
3123 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3124 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
3125 "Tahoma","Times New Roman", /* FIXME unverified */
3126 "Fixedsys,177", "System,177",
3127 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3128 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3129 { 0 }, { 0 }, { 0 }
3131 /* Arabic */
3132 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3133 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
3134 "Tahoma","Times New Roman", /* FIXME unverified */
3135 "Fixedsys,178", "System,178",
3136 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3137 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3138 { 0 }, { 0 }, { 0 }
3140 /* Baltic */
3141 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3142 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
3143 "Tahoma","Times New Roman", /* FIXME unverified */
3144 "Fixedsys,186", "System,186",
3145 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3146 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3147 { "Arial Baltic,0", "Arial,186" },
3148 { "Courier New Baltic,0", "Courier New,186" },
3149 { "Times New Roman Baltic,0", "Times New Roman,186" }
3151 /* Vietnamese */
3152 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3153 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3154 "Tahoma","Times New Roman", /* FIXME unverified */
3155 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3156 { 0 }, { 0 }, { 0 }
3158 /* Thai */
3159 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3160 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
3161 "Tahoma","Times New Roman", /* FIXME unverified */
3162 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3163 { 0 }, { 0 }, { 0 }
3165 /* Japanese */
3166 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3167 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
3168 "MS UI Gothic","MS Serif",
3169 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3170 { 0 }, { 0 }, { 0 }
3172 /* Chinese Simplified */
3173 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3174 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3175 "SimSun", "NSimSun",
3176 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3177 { 0 }, { 0 }, { 0 }
3179 /* Korean */
3180 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3181 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3182 "Gulim", "Batang",
3183 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3184 { 0 }, { 0 }, { 0 }
3186 /* Chinese Traditional */
3187 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3188 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3189 "PMingLiU", "MingLiU",
3190 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3191 { 0 }, { 0 }, { 0 }
3195 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3197 return ( ansi_cp == 932 /* CP932 for Japanese */
3198 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3199 || ansi_cp == 949 /* CP949 for Korean */
3200 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3203 static inline HKEY create_fonts_NT_registry_key(void)
3205 HKEY hkey = 0;
3207 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3208 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3209 return hkey;
3212 static inline HKEY create_fonts_9x_registry_key(void)
3214 HKEY hkey = 0;
3216 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3217 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3218 return hkey;
3221 static inline HKEY create_config_fonts_registry_key(void)
3223 HKEY hkey = 0;
3225 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3226 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3227 return hkey;
3230 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
3232 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3233 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3234 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
3235 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3238 static void set_value_key(HKEY hkey, const char *name, const char *value)
3240 if (value)
3241 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3242 else if (name)
3243 RegDeleteValueA(hkey, name);
3246 static void update_font_info(void)
3248 char buf[40], cpbuf[40];
3249 DWORD len, type;
3250 HKEY hkey = 0;
3251 UINT i, ansi_cp = 0, oem_cp = 0;
3252 BOOL done = FALSE;
3254 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3255 return;
3257 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3258 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3259 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3260 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3261 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3263 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3264 if (is_dbcs_ansi_cp(ansi_cp))
3265 use_default_fallback = TRUE;
3267 len = sizeof(buf);
3268 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3270 if (!strcmp( buf, cpbuf )) /* already set correctly */
3272 RegCloseKey(hkey);
3273 return;
3275 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
3277 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
3279 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3280 RegCloseKey(hkey);
3282 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3284 HKEY hkey;
3286 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3287 nls_update_font_list[i].oem_cp == oem_cp)
3289 hkey = create_config_fonts_registry_key();
3290 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3291 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3292 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3293 RegCloseKey(hkey);
3295 hkey = create_fonts_NT_registry_key();
3296 add_font_list(hkey, &nls_update_font_list[i]);
3297 RegCloseKey(hkey);
3299 hkey = create_fonts_9x_registry_key();
3300 add_font_list(hkey, &nls_update_font_list[i]);
3301 RegCloseKey(hkey);
3303 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3305 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3306 strlen(nls_update_font_list[i].shelldlg)+1);
3307 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3308 strlen(nls_update_font_list[i].tmsrmn)+1);
3310 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3311 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3312 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3313 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3314 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3315 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3316 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3317 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3319 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3320 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3321 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3323 RegCloseKey(hkey);
3325 done = TRUE;
3327 else
3329 /* Delete the FontSubstitutes from other locales */
3330 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3332 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3333 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3334 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3335 RegCloseKey(hkey);
3339 if (!done)
3340 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3343 static BOOL init_freetype(void)
3345 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3346 if(!ft_handle) {
3347 WINE_MESSAGE(
3348 "Wine cannot find the FreeType font library. To enable Wine to\n"
3349 "use TrueType fonts please install a version of FreeType greater than\n"
3350 "or equal to 2.0.5.\n"
3351 "http://www.freetype.org\n");
3352 return FALSE;
3355 #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;}
3357 LOAD_FUNCPTR(FT_Done_Face)
3358 LOAD_FUNCPTR(FT_Get_Char_Index)
3359 LOAD_FUNCPTR(FT_Get_First_Char)
3360 LOAD_FUNCPTR(FT_Get_Module)
3361 LOAD_FUNCPTR(FT_Get_Next_Char)
3362 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3363 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3364 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3365 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3366 LOAD_FUNCPTR(FT_Init_FreeType)
3367 LOAD_FUNCPTR(FT_Library_Version)
3368 LOAD_FUNCPTR(FT_Load_Glyph)
3369 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3370 LOAD_FUNCPTR(FT_Matrix_Multiply)
3371 #ifndef FT_MULFIX_INLINED
3372 LOAD_FUNCPTR(FT_MulFix)
3373 #endif
3374 LOAD_FUNCPTR(FT_New_Face)
3375 LOAD_FUNCPTR(FT_New_Memory_Face)
3376 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3377 LOAD_FUNCPTR(FT_Outline_Transform)
3378 LOAD_FUNCPTR(FT_Outline_Translate)
3379 LOAD_FUNCPTR(FT_Render_Glyph)
3380 LOAD_FUNCPTR(FT_Select_Charmap)
3381 LOAD_FUNCPTR(FT_Set_Charmap)
3382 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3383 LOAD_FUNCPTR(FT_Vector_Transform)
3384 LOAD_FUNCPTR(FT_Vector_Unit)
3385 #undef LOAD_FUNCPTR
3386 /* Don't warn if these ones are missing */
3387 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3388 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3389 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3390 #endif
3392 if(pFT_Init_FreeType(&library) != 0) {
3393 ERR("Can't init FreeType library\n");
3394 wine_dlclose(ft_handle, NULL, 0);
3395 ft_handle = NULL;
3396 return FALSE;
3398 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3400 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3401 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3402 ((FT_Version.minor << 8) & 0x00ff00) |
3403 ((FT_Version.patch ) & 0x0000ff);
3405 font_driver = &freetype_funcs;
3406 return TRUE;
3408 sym_not_found:
3409 WINE_MESSAGE(
3410 "Wine cannot find certain functions that it needs inside the FreeType\n"
3411 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3412 "FreeType to at least version 2.1.4.\n"
3413 "http://www.freetype.org\n");
3414 wine_dlclose(ft_handle, NULL, 0);
3415 ft_handle = NULL;
3416 return FALSE;
3419 static void init_font_list(void)
3421 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3422 static const WCHAR pathW[] = {'P','a','t','h',0};
3423 HKEY hkey;
3424 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3425 WCHAR windowsdir[MAX_PATH];
3426 char *unixname;
3427 const char *home;
3428 const char *data_dir;
3430 delete_external_font_keys();
3432 /* load the system bitmap fonts */
3433 load_system_fonts();
3435 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3436 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3437 strcatW(windowsdir, fontsW);
3438 if((unixname = wine_get_unix_file_name(windowsdir)))
3440 ReadFontDir(unixname, FALSE);
3441 HeapFree(GetProcessHeap(), 0, unixname);
3444 /* load the system truetype fonts */
3445 data_dir = wine_get_data_dir();
3446 if (!data_dir) data_dir = wine_get_build_dir();
3447 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3449 strcpy(unixname, data_dir);
3450 strcat(unixname, "/fonts/");
3451 ReadFontDir(unixname, TRUE);
3452 HeapFree(GetProcessHeap(), 0, unixname);
3455 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3456 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3457 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3458 will skip these. */
3459 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3460 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3461 &hkey) == ERROR_SUCCESS)
3463 LPWSTR data, valueW;
3464 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3465 &valuelen, &datalen, NULL, NULL);
3467 valuelen++; /* returned value doesn't include room for '\0' */
3468 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3469 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3470 if (valueW && data)
3472 dlen = datalen * sizeof(WCHAR);
3473 vlen = valuelen;
3474 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3475 &dlen) == ERROR_SUCCESS)
3477 if(data[0] && (data[1] == ':'))
3479 if((unixname = wine_get_unix_file_name(data)))
3481 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3482 HeapFree(GetProcessHeap(), 0, unixname);
3485 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3487 WCHAR pathW[MAX_PATH];
3488 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3489 BOOL added = FALSE;
3491 sprintfW(pathW, fmtW, windowsdir, data);
3492 if((unixname = wine_get_unix_file_name(pathW)))
3494 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3495 HeapFree(GetProcessHeap(), 0, unixname);
3497 if (!added)
3498 load_font_from_data_dir(data);
3500 /* reset dlen and vlen */
3501 dlen = datalen;
3502 vlen = valuelen;
3505 HeapFree(GetProcessHeap(), 0, data);
3506 HeapFree(GetProcessHeap(), 0, valueW);
3507 RegCloseKey(hkey);
3510 load_fontconfig_fonts();
3512 /* then look in any directories that we've specified in the config file */
3513 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3514 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3516 DWORD len;
3517 LPWSTR valueW;
3518 LPSTR valueA, ptr;
3520 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3522 len += sizeof(WCHAR);
3523 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3524 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3526 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3527 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3528 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3529 TRACE( "got font path %s\n", debugstr_a(valueA) );
3530 ptr = valueA;
3531 while (ptr)
3533 LPSTR next = strchr( ptr, ':' );
3534 if (next) *next++ = 0;
3535 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3536 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3538 strcpy( unixname, home );
3539 strcat( unixname, ptr + 1 );
3540 ReadFontDir( unixname, TRUE );
3541 HeapFree( GetProcessHeap(), 0, unixname );
3543 else
3544 ReadFontDir( ptr, TRUE );
3545 ptr = next;
3547 HeapFree( GetProcessHeap(), 0, valueA );
3549 HeapFree( GetProcessHeap(), 0, valueW );
3551 RegCloseKey(hkey);
3554 #ifdef __APPLE__
3555 /* Mac default font locations. */
3556 ReadFontDir( "/Library/Fonts", TRUE );
3557 ReadFontDir( "/Network/Library/Fonts", TRUE );
3558 ReadFontDir( "/System/Library/Fonts", TRUE );
3559 if ((home = getenv( "HOME" )))
3561 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3562 strcpy( unixname, home );
3563 strcat( unixname, "/Library/Fonts" );
3564 ReadFontDir( unixname, TRUE);
3565 HeapFree( GetProcessHeap(), 0, unixname );
3567 #endif
3570 static BOOL move_to_front(const WCHAR *name)
3572 Family *family, *cursor2;
3573 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3575 if(!strcmpiW(family->FamilyName, name))
3577 list_remove(&family->entry);
3578 list_add_head(&font_list, &family->entry);
3579 return TRUE;
3582 return FALSE;
3585 static BOOL set_default(const WCHAR **name_list)
3587 while (*name_list)
3589 if (move_to_front(*name_list)) return TRUE;
3590 name_list++;
3593 return FALSE;
3596 static void reorder_font_list(void)
3598 set_default( default_serif_list );
3599 set_default( default_fixed_list );
3600 set_default( default_sans_list );
3603 /*************************************************************
3604 * WineEngInit
3606 * Initialize FreeType library and create a list of available faces
3608 BOOL WineEngInit(void)
3610 HKEY hkey_font_cache;
3611 DWORD disposition;
3612 HANDLE font_mutex;
3614 /* update locale dependent font info in registry */
3615 update_font_info();
3617 if(!init_freetype()) return FALSE;
3619 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3621 ERR("Failed to create font mutex\n");
3622 return FALSE;
3624 WaitForSingleObject(font_mutex, INFINITE);
3626 create_font_cache_key(&hkey_font_cache, &disposition);
3628 if(disposition == REG_CREATED_NEW_KEY)
3629 init_font_list();
3630 else
3631 load_font_list_from_cache(hkey_font_cache);
3633 RegCloseKey(hkey_font_cache);
3635 reorder_font_list();
3637 DumpFontList();
3638 LoadSubstList();
3639 DumpSubstList();
3640 LoadReplaceList();
3642 if(disposition == REG_CREATED_NEW_KEY)
3643 update_reg_entries();
3645 init_system_links();
3647 ReleaseMutex(font_mutex);
3648 return TRUE;
3652 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3654 TT_OS2 *pOS2;
3655 TT_HoriHeader *pHori;
3657 LONG ppem;
3659 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3660 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3662 if(height == 0) height = 16;
3664 /* Calc. height of EM square:
3666 * For +ve lfHeight we have
3667 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3668 * Re-arranging gives:
3669 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3671 * For -ve lfHeight we have
3672 * |lfHeight| = ppem
3673 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3674 * with il = winAscent + winDescent - units_per_em]
3678 if(height > 0) {
3679 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3680 ppem = MulDiv(ft_face->units_per_EM, height,
3681 pHori->Ascender - pHori->Descender);
3682 else
3683 ppem = MulDiv(ft_face->units_per_EM, height,
3684 pOS2->usWinAscent + pOS2->usWinDescent);
3686 else
3687 ppem = -height;
3689 return ppem;
3692 static struct font_mapping *map_font_file( const char *name )
3694 struct font_mapping *mapping;
3695 struct stat st;
3696 int fd;
3698 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3699 if (fstat( fd, &st ) == -1) goto error;
3701 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3703 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3705 mapping->refcount++;
3706 close( fd );
3707 return mapping;
3710 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3711 goto error;
3713 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3714 close( fd );
3716 if (mapping->data == MAP_FAILED)
3718 HeapFree( GetProcessHeap(), 0, mapping );
3719 return NULL;
3721 mapping->refcount = 1;
3722 mapping->dev = st.st_dev;
3723 mapping->ino = st.st_ino;
3724 mapping->size = st.st_size;
3725 list_add_tail( &mappings_list, &mapping->entry );
3726 return mapping;
3728 error:
3729 close( fd );
3730 return NULL;
3733 static void unmap_font_file( struct font_mapping *mapping )
3735 if (!--mapping->refcount)
3737 list_remove( &mapping->entry );
3738 munmap( mapping->data, mapping->size );
3739 HeapFree( GetProcessHeap(), 0, mapping );
3743 static LONG load_VDMX(GdiFont*, LONG);
3745 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3747 FT_Error err;
3748 FT_Face ft_face;
3749 void *data_ptr;
3750 DWORD data_size;
3752 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3754 if (face->file)
3756 if (!(font->mapping = map_font_file( face->file )))
3758 WARN("failed to map %s\n", debugstr_a(face->file));
3759 return 0;
3761 data_ptr = font->mapping->data;
3762 data_size = font->mapping->size;
3764 else
3766 data_ptr = face->font_data_ptr;
3767 data_size = face->font_data_size;
3770 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3771 if(err) {
3772 ERR("FT_New_Face rets %d\n", err);
3773 return 0;
3776 /* set it here, as load_VDMX needs it */
3777 font->ft_face = ft_face;
3779 if(FT_IS_SCALABLE(ft_face)) {
3780 /* load the VDMX table if we have one */
3781 font->ppem = load_VDMX(font, height);
3782 if(font->ppem == 0)
3783 font->ppem = calc_ppem_for_height(ft_face, height);
3784 TRACE("height %d => ppem %d\n", height, font->ppem);
3786 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3787 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3788 } else {
3789 font->ppem = height;
3790 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3791 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3793 return ft_face;
3797 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3799 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3800 a single face with the requested charset. The idea is to check if
3801 the selected font supports the current ANSI codepage, if it does
3802 return the corresponding charset, else return the first charset */
3804 CHARSETINFO csi;
3805 int acp = GetACP(), i;
3806 DWORD fs0;
3808 *cp = acp;
3809 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3811 const SYSTEM_LINKS *font_link;
3813 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3814 return csi.ciCharset;
3816 font_link = find_font_link(family_name);
3817 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3818 return csi.ciCharset;
3821 for(i = 0; i < 32; i++) {
3822 fs0 = 1L << i;
3823 if(face->fs.fsCsb[0] & fs0) {
3824 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3825 *cp = csi.ciACP;
3826 return csi.ciCharset;
3828 else
3829 FIXME("TCI failing on %x\n", fs0);
3833 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3834 face->fs.fsCsb[0], face->file);
3835 *cp = acp;
3836 return DEFAULT_CHARSET;
3839 static GdiFont *alloc_font(void)
3841 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3842 ret->gmsize = 1;
3843 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3844 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3845 ret->potm = NULL;
3846 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3847 ret->total_kern_pairs = (DWORD)-1;
3848 ret->kern_pairs = NULL;
3849 list_init(&ret->hfontlist);
3850 list_init(&ret->child_fonts);
3851 return ret;
3854 static void free_font(GdiFont *font)
3856 struct list *cursor, *cursor2;
3857 DWORD i;
3859 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3861 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3862 list_remove(cursor);
3863 if(child->font)
3864 free_font(child->font);
3865 HeapFree(GetProcessHeap(), 0, child);
3868 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3870 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3871 DeleteObject(hfontlist->hfont);
3872 list_remove(&hfontlist->entry);
3873 HeapFree(GetProcessHeap(), 0, hfontlist);
3876 if (font->ft_face) pFT_Done_Face(font->ft_face);
3877 if (font->mapping) unmap_font_file( font->mapping );
3878 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3879 HeapFree(GetProcessHeap(), 0, font->potm);
3880 HeapFree(GetProcessHeap(), 0, font->name);
3881 for (i = 0; i < font->gmsize; i++)
3882 HeapFree(GetProcessHeap(),0,font->gm[i]);
3883 HeapFree(GetProcessHeap(), 0, font->gm);
3884 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3885 HeapFree(GetProcessHeap(), 0, font);
3889 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3891 FT_Face ft_face = font->ft_face;
3892 FT_ULong len;
3893 FT_Error err;
3895 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3897 if(!buf)
3898 len = 0;
3899 else
3900 len = cbData;
3902 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3904 /* make sure value of len is the value freetype says it needs */
3905 if (buf && len)
3907 FT_ULong needed = 0;
3908 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3909 if( !err && needed < len) len = needed;
3911 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3912 if (err)
3914 TRACE("Can't find table %c%c%c%c\n",
3915 /* bytes were reversed */
3916 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3917 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3918 return GDI_ERROR;
3920 return len;
3923 /*************************************************************
3924 * load_VDMX
3926 * load the vdmx entry for the specified height
3929 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3930 ( ( (FT_ULong)_x4 << 24 ) | \
3931 ( (FT_ULong)_x3 << 16 ) | \
3932 ( (FT_ULong)_x2 << 8 ) | \
3933 (FT_ULong)_x1 )
3935 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3937 typedef struct {
3938 BYTE bCharSet;
3939 BYTE xRatio;
3940 BYTE yStartRatio;
3941 BYTE yEndRatio;
3942 } Ratios;
3944 typedef struct {
3945 WORD recs;
3946 BYTE startsz;
3947 BYTE endsz;
3948 } VDMX_group;
3950 static LONG load_VDMX(GdiFont *font, LONG height)
3952 WORD hdr[3], tmp;
3953 VDMX_group group;
3954 BYTE devXRatio, devYRatio;
3955 USHORT numRecs, numRatios;
3956 DWORD result, offset = -1;
3957 LONG ppem = 0;
3958 int i;
3960 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3962 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3963 return ppem;
3965 /* FIXME: need the real device aspect ratio */
3966 devXRatio = 1;
3967 devYRatio = 1;
3969 numRecs = GET_BE_WORD(hdr[1]);
3970 numRatios = GET_BE_WORD(hdr[2]);
3972 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3973 for(i = 0; i < numRatios; i++) {
3974 Ratios ratio;
3976 offset = (3 * 2) + (i * sizeof(Ratios));
3977 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3978 offset = -1;
3980 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3982 if((ratio.xRatio == 0 &&
3983 ratio.yStartRatio == 0 &&
3984 ratio.yEndRatio == 0) ||
3985 (devXRatio == ratio.xRatio &&
3986 devYRatio >= ratio.yStartRatio &&
3987 devYRatio <= ratio.yEndRatio))
3989 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3990 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3991 offset = GET_BE_WORD(tmp);
3992 break;
3996 if(offset == -1) {
3997 FIXME("No suitable ratio found\n");
3998 return ppem;
4001 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4002 USHORT recs;
4003 BYTE startsz, endsz;
4004 WORD *vTable;
4006 recs = GET_BE_WORD(group.recs);
4007 startsz = group.startsz;
4008 endsz = group.endsz;
4010 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4012 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4013 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4014 if(result == GDI_ERROR) {
4015 FIXME("Failed to retrieve vTable\n");
4016 goto end;
4019 if(height > 0) {
4020 for(i = 0; i < recs; i++) {
4021 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4022 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4023 ppem = GET_BE_WORD(vTable[i * 3]);
4025 if(yMax + -yMin == height) {
4026 font->yMax = yMax;
4027 font->yMin = yMin;
4028 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4029 break;
4031 if(yMax + -yMin > height) {
4032 if(--i < 0) {
4033 ppem = 0;
4034 goto end; /* failed */
4036 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4037 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4038 ppem = GET_BE_WORD(vTable[i * 3]);
4039 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4040 break;
4043 if(!font->yMax) {
4044 ppem = 0;
4045 TRACE("ppem not found for height %d\n", height);
4048 end:
4049 HeapFree(GetProcessHeap(), 0, vTable);
4052 return ppem;
4055 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4057 if(font->font_desc.hash != fd->hash) return TRUE;
4058 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4059 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4060 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4061 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4064 static void calc_hash(FONT_DESC *pfd)
4066 DWORD hash = 0, *ptr, two_chars;
4067 WORD *pwc;
4068 unsigned int i;
4070 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4071 hash ^= *ptr;
4072 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4073 hash ^= *ptr;
4074 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4075 two_chars = *ptr;
4076 pwc = (WCHAR *)&two_chars;
4077 if(!*pwc) break;
4078 *pwc = toupperW(*pwc);
4079 pwc++;
4080 *pwc = toupperW(*pwc);
4081 hash ^= two_chars;
4082 if(!*pwc) break;
4084 hash ^= !pfd->can_use_bitmap;
4085 pfd->hash = hash;
4086 return;
4089 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4091 GdiFont *ret;
4092 FONT_DESC fd;
4093 HFONTLIST *hflist;
4094 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4096 fd.lf = *plf;
4097 fd.matrix = *pmat;
4098 fd.can_use_bitmap = can_use_bitmap;
4099 calc_hash(&fd);
4101 /* try the child list */
4102 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4103 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4104 if(!fontcmp(ret, &fd)) {
4105 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4106 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4107 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4108 if(hflist->hfont == hfont)
4109 return ret;
4114 /* try the in-use list */
4115 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4116 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4117 if(!fontcmp(ret, &fd)) {
4118 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4119 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4120 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4121 if(hflist->hfont == hfont)
4122 return ret;
4124 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4125 hflist->hfont = hfont;
4126 list_add_head(&ret->hfontlist, &hflist->entry);
4127 return ret;
4131 /* then the unused list */
4132 font_elem_ptr = list_head(&unused_gdi_font_list);
4133 while(font_elem_ptr) {
4134 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4135 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4136 if(!fontcmp(ret, &fd)) {
4137 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4138 assert(list_empty(&ret->hfontlist));
4139 TRACE("Found %p in unused list\n", ret);
4140 list_remove(&ret->entry);
4141 list_add_head(&gdi_font_list, &ret->entry);
4142 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4143 hflist->hfont = hfont;
4144 list_add_head(&ret->hfontlist, &hflist->entry);
4145 return ret;
4148 return NULL;
4151 static void add_to_cache(GdiFont *font)
4153 static DWORD cache_num = 1;
4155 font->cache_num = cache_num++;
4156 list_add_head(&gdi_font_list, &font->entry);
4159 /*************************************************************
4160 * create_child_font_list
4162 static BOOL create_child_font_list(GdiFont *font)
4164 BOOL ret = FALSE;
4165 SYSTEM_LINKS *font_link;
4166 CHILD_FONT *font_link_entry, *new_child;
4167 FontSubst *psub;
4168 WCHAR* font_name;
4170 psub = get_font_subst(&font_subst_list, font->name, -1);
4171 font_name = psub ? psub->to.name : font->name;
4172 font_link = find_font_link(font_name);
4173 if (font_link != NULL)
4175 TRACE("found entry in system list\n");
4176 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4178 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4179 new_child->face = font_link_entry->face;
4180 new_child->font = NULL;
4181 list_add_tail(&font->child_fonts, &new_child->entry);
4182 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4184 ret = TRUE;
4187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4188 * Sans Serif. This is how asian windows get default fallbacks for fonts
4190 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4191 font->charset != OEM_CHARSET &&
4192 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4194 font_link = find_font_link(szDefaultFallbackLink);
4195 if (font_link != NULL)
4197 TRACE("found entry in default fallback list\n");
4198 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4200 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4201 new_child->face = font_link_entry->face;
4202 new_child->font = NULL;
4203 list_add_tail(&font->child_fonts, &new_child->entry);
4204 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4206 ret = TRUE;
4210 return ret;
4213 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4215 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4217 if (pFT_Set_Charmap)
4219 FT_Int i;
4220 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4222 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4224 for (i = 0; i < ft_face->num_charmaps; i++)
4226 if (ft_face->charmaps[i]->encoding == encoding)
4228 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4229 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4231 switch (ft_face->charmaps[i]->platform_id)
4233 default:
4234 cmap_def = ft_face->charmaps[i];
4235 break;
4236 case 0: /* Apple Unicode */
4237 cmap0 = ft_face->charmaps[i];
4238 break;
4239 case 1: /* Macintosh */
4240 cmap1 = ft_face->charmaps[i];
4241 break;
4242 case 2: /* ISO */
4243 cmap2 = ft_face->charmaps[i];
4244 break;
4245 case 3: /* Microsoft */
4246 cmap3 = ft_face->charmaps[i];
4247 break;
4251 if (cmap3) /* prefer Microsoft cmap table */
4252 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4253 else if (cmap1)
4254 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4255 else if (cmap2)
4256 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4257 else if (cmap0)
4258 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4259 else if (cmap_def)
4260 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4262 return ft_err == FT_Err_Ok;
4265 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4269 /*************************************************************
4270 * freetype_CreateDC
4272 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4273 LPCWSTR output, const DEVMODEW *devmode )
4275 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4277 if (!physdev) return FALSE;
4278 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4279 return TRUE;
4283 /*************************************************************
4284 * freetype_DeleteDC
4286 static BOOL freetype_DeleteDC( PHYSDEV dev )
4288 struct freetype_physdev *physdev = get_freetype_dev( dev );
4289 HeapFree( GetProcessHeap(), 0, physdev );
4290 return TRUE;
4294 /*************************************************************
4295 * freetype_SelectFont
4297 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4299 struct freetype_physdev *physdev = get_freetype_dev( dev );
4300 GdiFont *ret;
4301 Face *face, *best, *best_bitmap;
4302 Family *family, *last_resort_family;
4303 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4304 INT height, width = 0;
4305 unsigned int score = 0, new_score;
4306 signed int diff = 0, newdiff;
4307 BOOL bd, it, can_use_bitmap, want_vertical;
4308 LOGFONTW lf;
4309 CHARSETINFO csi;
4310 HFONTLIST *hflist;
4311 FMAT2 dcmat;
4312 FontSubst *psub = NULL;
4313 DC *dc = get_dc_ptr( dev->hdc );
4314 const SYSTEM_LINKS *font_link;
4316 if (!hfont) /* notification that the font has been changed by another driver */
4318 dc->gdiFont = NULL;
4319 physdev->font = NULL;
4320 release_dc_ptr( dc );
4321 return 0;
4324 GetObjectW( hfont, sizeof(lf), &lf );
4325 lf.lfWidth = abs(lf.lfWidth);
4327 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4329 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4330 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4331 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4332 lf.lfEscapement);
4334 if(dc->GraphicsMode == GM_ADVANCED)
4336 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4337 /* Try to avoid not necessary glyph transformations */
4338 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4340 lf.lfHeight *= fabs(dcmat.eM11);
4341 lf.lfWidth *= fabs(dcmat.eM11);
4342 dcmat.eM11 = dcmat.eM22 = 1.0;
4345 else
4347 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4348 font scaling abilities. */
4349 dcmat.eM11 = dcmat.eM22 = 1.0;
4350 dcmat.eM21 = dcmat.eM12 = 0;
4351 if (dc->vport2WorldValid)
4353 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4354 lf.lfOrientation = -lf.lfOrientation;
4355 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4356 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4360 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4361 dcmat.eM21, dcmat.eM22);
4363 GDI_CheckNotLock();
4364 EnterCriticalSection( &freetype_cs );
4366 /* check the cache first */
4367 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4368 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4369 goto done;
4372 if(list_empty(&font_list)) /* No fonts installed */
4374 TRACE("No fonts installed\n");
4375 goto done;
4378 TRACE("not in cache\n");
4379 ret = alloc_font();
4381 ret->font_desc.matrix = dcmat;
4382 ret->font_desc.lf = lf;
4383 ret->font_desc.can_use_bitmap = can_use_bitmap;
4384 calc_hash(&ret->font_desc);
4385 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4386 hflist->hfont = hfont;
4387 list_add_head(&ret->hfontlist, &hflist->entry);
4389 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4390 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4391 original value lfCharSet. Note this is a special case for
4392 Symbol and doesn't happen at least for "Wingdings*" */
4394 if(!strcmpiW(lf.lfFaceName, SymbolW))
4395 lf.lfCharSet = SYMBOL_CHARSET;
4397 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4398 switch(lf.lfCharSet) {
4399 case DEFAULT_CHARSET:
4400 csi.fs.fsCsb[0] = 0;
4401 break;
4402 default:
4403 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4404 csi.fs.fsCsb[0] = 0;
4405 break;
4409 family = NULL;
4410 if(lf.lfFaceName[0] != '\0') {
4411 CHILD_FONT *font_link_entry;
4412 LPWSTR FaceName = lf.lfFaceName;
4414 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4416 if(psub) {
4417 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4418 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4419 if (psub->to.charset != -1)
4420 lf.lfCharSet = psub->to.charset;
4423 /* We want a match on name and charset or just name if
4424 charset was DEFAULT_CHARSET. If the latter then
4425 we fixup the returned charset later in get_nearest_charset
4426 where we'll either use the charset of the current ansi codepage
4427 or if that's unavailable the first charset that the font supports.
4429 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4430 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4431 if (!strcmpiW(family->FamilyName, FaceName) ||
4432 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4434 font_link = find_font_link(family->FamilyName);
4435 face_list = get_face_list_from_family(family);
4436 LIST_FOR_EACH(face_elem_ptr, face_list) {
4437 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4438 if (!(face->scalable || can_use_bitmap))
4439 continue;
4440 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4441 goto found;
4442 if (font_link != NULL &&
4443 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4444 goto found;
4445 if (!csi.fs.fsCsb[0])
4446 goto found;
4451 /* Search by full face name. */
4452 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4453 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4454 face_list = get_face_list_from_family(family);
4455 LIST_FOR_EACH(face_elem_ptr, face_list) {
4456 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4457 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4458 (face->scalable || can_use_bitmap))
4460 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4461 goto found_face;
4462 font_link = find_font_link(family->FamilyName);
4463 if (font_link != NULL &&
4464 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4465 goto found_face;
4471 * Try check the SystemLink list first for a replacement font.
4472 * We may find good replacements there.
4474 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4476 if(!strcmpiW(font_link->font_name, FaceName) ||
4477 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4479 TRACE("found entry in system list\n");
4480 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4482 const SYSTEM_LINKS *links;
4484 face = font_link_entry->face;
4485 if (!(face->scalable || can_use_bitmap))
4486 continue;
4487 family = face->family;
4488 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4489 goto found;
4490 links = find_font_link(family->FamilyName);
4491 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4492 goto found;
4498 psub = NULL; /* substitution is no more relevant */
4500 /* If requested charset was DEFAULT_CHARSET then try using charset
4501 corresponding to the current ansi codepage */
4502 if (!csi.fs.fsCsb[0])
4504 INT acp = GetACP();
4505 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4506 FIXME("TCI failed on codepage %d\n", acp);
4507 csi.fs.fsCsb[0] = 0;
4508 } else
4509 lf.lfCharSet = csi.ciCharset;
4512 want_vertical = (lf.lfFaceName[0] == '@');
4514 /* Face families are in the top 4 bits of lfPitchAndFamily,
4515 so mask with 0xF0 before testing */
4517 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4518 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4519 strcpyW(lf.lfFaceName, defFixed);
4520 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4521 strcpyW(lf.lfFaceName, defSerif);
4522 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4523 strcpyW(lf.lfFaceName, defSans);
4524 else
4525 strcpyW(lf.lfFaceName, defSans);
4526 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4527 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4528 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4529 font_link = find_font_link(family->FamilyName);
4530 face_list = get_face_list_from_family(family);
4531 LIST_FOR_EACH(face_elem_ptr, face_list) {
4532 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4533 if (!(face->scalable || can_use_bitmap))
4534 continue;
4535 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4536 goto found;
4537 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4538 goto found;
4543 last_resort_family = NULL;
4544 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4545 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4546 font_link = find_font_link(family->FamilyName);
4547 face_list = get_face_list_from_family(family);
4548 LIST_FOR_EACH(face_elem_ptr, face_list) {
4549 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4550 if(face->vertical == want_vertical &&
4551 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4552 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4553 if(face->scalable)
4554 goto found;
4555 if(can_use_bitmap && !last_resort_family)
4556 last_resort_family = family;
4561 if(last_resort_family) {
4562 family = last_resort_family;
4563 csi.fs.fsCsb[0] = 0;
4564 goto found;
4567 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4568 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4569 face_list = get_face_list_from_family(family);
4570 LIST_FOR_EACH(face_elem_ptr, face_list) {
4571 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4572 if(face->scalable && face->vertical == want_vertical) {
4573 csi.fs.fsCsb[0] = 0;
4574 WARN("just using first face for now\n");
4575 goto found;
4577 if(can_use_bitmap && !last_resort_family)
4578 last_resort_family = family;
4581 if(!last_resort_family) {
4582 FIXME("can't find a single appropriate font - bailing\n");
4583 free_font(ret);
4584 ret = NULL;
4585 goto done;
4588 WARN("could only find a bitmap font - this will probably look awful!\n");
4589 family = last_resort_family;
4590 csi.fs.fsCsb[0] = 0;
4592 found:
4593 it = lf.lfItalic ? 1 : 0;
4594 bd = lf.lfWeight > 550 ? 1 : 0;
4596 height = lf.lfHeight;
4598 face = best = best_bitmap = NULL;
4599 font_link = find_font_link(family->FamilyName);
4600 face_list = get_face_list_from_family(family);
4601 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4603 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4604 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4605 !csi.fs.fsCsb[0])
4607 BOOL italic, bold;
4609 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4610 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4611 new_score = (italic ^ it) + (bold ^ bd);
4612 if(!best || new_score <= score)
4614 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4615 italic, bold, it, bd);
4616 score = new_score;
4617 best = face;
4618 if(best->scalable && score == 0) break;
4619 if(!best->scalable)
4621 if(height > 0)
4622 newdiff = height - (signed int)(best->size.height);
4623 else
4624 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4625 if(!best_bitmap || new_score < score ||
4626 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4628 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4629 diff = newdiff;
4630 best_bitmap = best;
4631 if(score == 0 && diff == 0) break;
4637 if(best)
4638 face = best->scalable ? best : best_bitmap;
4639 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4640 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4642 found_face:
4643 height = lf.lfHeight;
4645 ret->fs = face->fs;
4647 if(csi.fs.fsCsb[0]) {
4648 ret->charset = lf.lfCharSet;
4649 ret->codepage = csi.ciACP;
4651 else
4652 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4654 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4655 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4657 ret->aveWidth = height ? lf.lfWidth : 0;
4659 if(!face->scalable) {
4660 /* Windows uses integer scaling factors for bitmap fonts */
4661 INT scale, scaled_height;
4662 GdiFont *cachedfont;
4664 /* FIXME: rotation of bitmap fonts is ignored */
4665 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4666 if (ret->aveWidth)
4667 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4668 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4669 dcmat.eM11 = dcmat.eM22 = 1.0;
4670 /* As we changed the matrix, we need to search the cache for the font again,
4671 * otherwise we might explode the cache. */
4672 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4673 TRACE("Found cached font after non-scalable matrix rescale!\n");
4674 free_font( ret );
4675 ret = cachedfont;
4676 goto done;
4678 calc_hash(&ret->font_desc);
4680 if (height != 0) height = diff;
4681 height += face->size.height;
4683 scale = (height + face->size.height - 1) / face->size.height;
4684 scaled_height = scale * face->size.height;
4685 /* Only jump to the next height if the difference <= 25% original height */
4686 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4687 /* The jump between unscaled and doubled is delayed by 1 */
4688 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4689 ret->scale_y = scale;
4691 width = face->size.x_ppem >> 6;
4692 height = face->size.y_ppem >> 6;
4694 else
4695 ret->scale_y = 1.0;
4696 TRACE("font scale y: %f\n", ret->scale_y);
4698 ret->ft_face = OpenFontFace(ret, face, width, height);
4700 if (!ret->ft_face)
4702 free_font( ret );
4703 ret = NULL;
4704 goto done;
4707 ret->ntmFlags = face->ntmFlags;
4709 if (ret->charset == SYMBOL_CHARSET &&
4710 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4711 /* No ops */
4713 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4714 /* No ops */
4716 else {
4717 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4720 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4721 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4722 ret->underline = lf.lfUnderline ? 0xff : 0;
4723 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4724 create_child_font_list(ret);
4726 if (face->vertical) /* We need to try to load the GSUB table */
4728 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4729 if (length != GDI_ERROR)
4731 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4732 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4733 TRACE("Loaded GSUB table of %i bytes\n",length);
4737 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4739 add_to_cache(ret);
4740 done:
4741 if (ret)
4743 dc->gdiFont = ret;
4744 physdev->font = ret;
4746 LeaveCriticalSection( &freetype_cs );
4747 release_dc_ptr( dc );
4748 return ret ? hfont : 0;
4751 static void dump_gdi_font_list(void)
4753 GdiFont *gdiFont;
4754 struct list *elem_ptr;
4756 TRACE("---------- gdiFont Cache ----------\n");
4757 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4758 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4759 TRACE("gdiFont=%p %s %d\n",
4760 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4763 TRACE("---------- Unused gdiFont Cache ----------\n");
4764 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4765 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4766 TRACE("gdiFont=%p %s %d\n",
4767 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4770 TRACE("---------- Child gdiFont Cache ----------\n");
4771 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4772 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4773 TRACE("gdiFont=%p %s %d\n",
4774 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4778 /*************************************************************
4779 * WineEngDestroyFontInstance
4781 * free the gdiFont associated with this handle
4784 BOOL WineEngDestroyFontInstance(HFONT handle)
4786 GdiFont *gdiFont;
4787 HFONTLIST *hflist;
4788 BOOL ret = FALSE;
4789 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4790 int i = 0;
4792 GDI_CheckNotLock();
4793 EnterCriticalSection( &freetype_cs );
4795 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4797 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4798 while(hfontlist_elem_ptr) {
4799 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4800 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4801 if(hflist->hfont == handle) {
4802 TRACE("removing child font %p from child list\n", gdiFont);
4803 list_remove(&gdiFont->entry);
4804 LeaveCriticalSection( &freetype_cs );
4805 return TRUE;
4810 TRACE("destroying hfont=%p\n", handle);
4811 if(TRACE_ON(font))
4812 dump_gdi_font_list();
4814 font_elem_ptr = list_head(&gdi_font_list);
4815 while(font_elem_ptr) {
4816 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4817 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4819 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4820 while(hfontlist_elem_ptr) {
4821 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4822 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4823 if(hflist->hfont == handle) {
4824 list_remove(&hflist->entry);
4825 HeapFree(GetProcessHeap(), 0, hflist);
4826 ret = TRUE;
4829 if(list_empty(&gdiFont->hfontlist)) {
4830 TRACE("Moving to Unused list\n");
4831 list_remove(&gdiFont->entry);
4832 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4837 font_elem_ptr = list_head(&unused_gdi_font_list);
4838 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4839 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4840 while(font_elem_ptr) {
4841 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4842 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4843 TRACE("freeing %p\n", gdiFont);
4844 list_remove(&gdiFont->entry);
4845 free_font(gdiFont);
4847 LeaveCriticalSection( &freetype_cs );
4848 return ret;
4851 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4853 HRSRC rsrc;
4854 HGLOBAL hMem;
4855 WCHAR *p;
4856 int i;
4858 id += IDS_FIRST_SCRIPT;
4859 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4860 if (!rsrc) return 0;
4861 hMem = LoadResource( gdi32_module, rsrc );
4862 if (!hMem) return 0;
4864 p = LockResource( hMem );
4865 id &= 0x000f;
4866 while (id--) p += *p + 1;
4868 i = min(LF_FACESIZE - 1, *p);
4869 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4870 buffer[i] = 0;
4871 return i;
4875 /***************************************************
4876 * create_enum_charset_list
4878 * This function creates charset enumeration list because in DEFAULT_CHARSET
4879 * case, the ANSI codepage's charset takes precedence over other charsets.
4880 * This function works as a filter other than DEFAULT_CHARSET case.
4882 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4884 CHARSETINFO csi;
4885 DWORD n = 0;
4887 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4888 csi.fs.fsCsb[0] != 0) {
4889 list->element[n].mask = csi.fs.fsCsb[0];
4890 list->element[n].charset = csi.ciCharset;
4891 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4892 n++;
4894 else { /* charset is DEFAULT_CHARSET or invalid. */
4895 INT acp, i;
4897 /* Set the current codepage's charset as the first element. */
4898 acp = GetACP();
4899 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4900 csi.fs.fsCsb[0] != 0) {
4901 list->element[n].mask = csi.fs.fsCsb[0];
4902 list->element[n].charset = csi.ciCharset;
4903 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4904 n++;
4907 /* Fill out left elements. */
4908 for (i = 0; i < 32; i++) {
4909 FONTSIGNATURE fs;
4910 fs.fsCsb[0] = 1L << i;
4911 fs.fsCsb[1] = 0;
4912 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4913 continue; /* skip, already added. */
4914 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4915 continue; /* skip, this is an invalid fsCsb bit. */
4917 list->element[n].mask = fs.fsCsb[0];
4918 list->element[n].charset = csi.ciCharset;
4919 load_script_name( i, list->element[n].name );
4920 n++;
4923 list->total = n;
4925 return n;
4928 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4929 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4931 GdiFont *font;
4932 LONG width, height;
4934 if (face->cached_enum_data)
4936 TRACE("Cached\n");
4937 *pelf = face->cached_enum_data->elf;
4938 *pntm = face->cached_enum_data->ntm;
4939 *ptype = face->cached_enum_data->type;
4940 return;
4943 font = alloc_font();
4945 if(face->scalable) {
4946 height = -2048; /* 2048 is the most common em size */
4947 width = 0;
4948 } else {
4949 height = face->size.y_ppem >> 6;
4950 width = face->size.x_ppem >> 6;
4952 font->scale_y = 1.0;
4954 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4956 free_font(font);
4957 return;
4960 font->name = strdupW(face->family->FamilyName);
4961 font->ntmFlags = face->ntmFlags;
4963 if (get_outline_text_metrics(font))
4965 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4967 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4969 lstrcpynW(pelf->elfLogFont.lfFaceName,
4970 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4971 LF_FACESIZE);
4972 lstrcpynW(pelf->elfFullName,
4973 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4974 LF_FULLFACESIZE);
4975 lstrcpynW(pelf->elfStyle,
4976 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4977 LF_FACESIZE);
4979 else
4981 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4983 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4985 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4986 if (face->FullName)
4987 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4988 else
4989 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4990 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4993 pntm->ntmTm.ntmFlags = face->ntmFlags;
4994 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4995 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4996 pntm->ntmFontSig = face->fs;
4998 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5000 pelf->elfLogFont.lfEscapement = 0;
5001 pelf->elfLogFont.lfOrientation = 0;
5002 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5003 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5004 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5005 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5006 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5007 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5008 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5009 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5010 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5011 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5012 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5014 *ptype = 0;
5015 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5016 *ptype |= TRUETYPE_FONTTYPE;
5017 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5018 *ptype |= DEVICE_FONTTYPE;
5019 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5020 *ptype |= RASTER_FONTTYPE;
5022 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5023 if (face->cached_enum_data)
5025 face->cached_enum_data->elf = *pelf;
5026 face->cached_enum_data->ntm = *pntm;
5027 face->cached_enum_data->type = *ptype;
5030 free_font(font);
5033 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
5035 static const WCHAR spaceW[] = { ' ', 0 };
5037 strcpyW(full_name, family_name);
5038 strcatW(full_name, spaceW);
5039 strcatW(full_name, style_name);
5042 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5044 const struct list *face_list, *face_elem_ptr;
5046 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5048 face_list = get_face_list_from_family(family);
5049 LIST_FOR_EACH(face_elem_ptr, face_list)
5051 WCHAR full_family_name[LF_FULLFACESIZE];
5052 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5054 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5056 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5057 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
5058 continue;
5061 create_full_name(full_family_name, family->FamilyName, face->StyleName);
5062 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
5065 return FALSE;
5068 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5070 WCHAR full_family_name[LF_FULLFACESIZE];
5072 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5074 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5076 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5077 debugstr_w(family_name), debugstr_w(face->StyleName));
5078 return FALSE;
5081 create_full_name(full_family_name, family_name, face->StyleName);
5082 return !strcmpiW(lf->lfFaceName, full_family_name);
5085 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5086 FONTENUMPROCW proc, LPARAM lparam)
5088 ENUMLOGFONTEXW elf;
5089 NEWTEXTMETRICEXW ntm;
5090 DWORD type = 0;
5091 int i;
5093 GetEnumStructs(face, &elf, &ntm, &type);
5094 for(i = 0; i < list->total; i++) {
5095 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5096 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5097 load_script_name( IDS_OEM_DOS, elf.elfScript );
5098 i = list->total; /* break out of loop after enumeration */
5099 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5100 continue;
5101 else {
5102 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5103 strcpyW(elf.elfScript, list->element[i].name);
5104 if (!elf.elfScript[0])
5105 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5107 /* Font Replacement */
5108 if (family != face->family)
5110 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5111 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
5113 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5114 debugstr_w(elf.elfLogFont.lfFaceName),
5115 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5116 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5117 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5118 ntm.ntmTm.ntmFlags);
5119 /* release section before callback (FIXME) */
5120 LeaveCriticalSection( &freetype_cs );
5121 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5122 EnterCriticalSection( &freetype_cs );
5124 return TRUE;
5127 /*************************************************************
5128 * freetype_EnumFonts
5130 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5132 Family *family;
5133 Face *face;
5134 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5135 LOGFONTW lf;
5136 struct enum_charset_list enum_charsets;
5138 if (!plf)
5140 lf.lfCharSet = DEFAULT_CHARSET;
5141 lf.lfPitchAndFamily = 0;
5142 lf.lfFaceName[0] = 0;
5143 plf = &lf;
5146 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5148 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5150 GDI_CheckNotLock();
5151 EnterCriticalSection( &freetype_cs );
5152 if(plf->lfFaceName[0]) {
5153 FontSubst *psub;
5154 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5156 if(psub) {
5157 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5158 debugstr_w(psub->to.name));
5159 lf = *plf;
5160 strcpyW(lf.lfFaceName, psub->to.name);
5161 plf = &lf;
5164 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5165 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5166 if(family_matches(family, plf)) {
5167 face_list = get_face_list_from_family(family);
5168 LIST_FOR_EACH(face_elem_ptr, face_list) {
5169 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5170 if (!face_matches(family->FamilyName, face, plf)) continue;
5171 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5175 } else {
5176 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5177 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5178 face_list = get_face_list_from_family(family);
5179 face_elem_ptr = list_head(face_list);
5180 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5181 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5184 LeaveCriticalSection( &freetype_cs );
5185 return TRUE;
5188 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5190 pt->x.value = vec->x >> 6;
5191 pt->x.fract = (vec->x & 0x3f) << 10;
5192 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5193 pt->y.value = vec->y >> 6;
5194 pt->y.fract = (vec->y & 0x3f) << 10;
5195 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5196 return;
5199 /***************************************************
5200 * According to the MSDN documentation on WideCharToMultiByte,
5201 * certain codepages cannot set the default_used parameter.
5202 * This returns TRUE if the codepage can set that parameter, false else
5203 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5205 static BOOL codepage_sets_default_used(UINT codepage)
5207 switch (codepage)
5209 case CP_UTF7:
5210 case CP_UTF8:
5211 case CP_SYMBOL:
5212 return FALSE;
5213 default:
5214 return TRUE;
5219 * GSUB Table handling functions
5222 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5224 const GSUB_CoverageFormat1* cf1;
5226 cf1 = table;
5228 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5230 int count = GET_BE_WORD(cf1->GlyphCount);
5231 int i;
5232 TRACE("Coverage Format 1, %i glyphs\n",count);
5233 for (i = 0; i < count; i++)
5234 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5235 return i;
5236 return -1;
5238 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5240 const GSUB_CoverageFormat2* cf2;
5241 int i;
5242 int count;
5243 cf2 = (const GSUB_CoverageFormat2*)cf1;
5245 count = GET_BE_WORD(cf2->RangeCount);
5246 TRACE("Coverage Format 2, %i ranges\n",count);
5247 for (i = 0; i < count; i++)
5249 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5250 return -1;
5251 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5252 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5254 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5255 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5258 return -1;
5260 else
5261 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5263 return -1;
5266 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5268 const GSUB_ScriptList *script;
5269 const GSUB_Script *deflt = NULL;
5270 int i;
5271 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5273 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5274 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5276 const GSUB_Script *scr;
5277 int offset;
5279 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5280 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5282 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5283 return scr;
5284 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5285 deflt = scr;
5287 return deflt;
5290 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5292 int i;
5293 int offset;
5294 const GSUB_LangSys *Lang;
5296 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5298 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5300 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5301 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5303 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5304 return Lang;
5306 offset = GET_BE_WORD(script->DefaultLangSys);
5307 if (offset)
5309 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5310 return Lang;
5312 return NULL;
5315 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5317 int i;
5318 const GSUB_FeatureList *feature;
5319 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5321 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5322 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5324 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5325 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5327 const GSUB_Feature *feat;
5328 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5329 return feat;
5332 return NULL;
5335 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5337 int i;
5338 int offset;
5339 const GSUB_LookupList *lookup;
5340 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5342 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5343 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5345 const GSUB_LookupTable *look;
5346 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5347 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5348 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5349 if (GET_BE_WORD(look->LookupType) != 1)
5350 FIXME("We only handle SubType 1\n");
5351 else
5353 int j;
5355 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5357 const GSUB_SingleSubstFormat1 *ssf1;
5358 offset = GET_BE_WORD(look->SubTable[j]);
5359 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5360 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5362 int offset = GET_BE_WORD(ssf1->Coverage);
5363 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5364 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5366 TRACE(" Glyph 0x%x ->",glyph);
5367 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5368 TRACE(" 0x%x\n",glyph);
5371 else
5373 const GSUB_SingleSubstFormat2 *ssf2;
5374 INT index;
5375 INT offset;
5377 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5378 offset = GET_BE_WORD(ssf1->Coverage);
5379 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5380 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5381 TRACE(" Coverage index %i\n",index);
5382 if (index != -1)
5384 TRACE(" Glyph is 0x%x ->",glyph);
5385 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5386 TRACE("0x%x\n",glyph);
5392 return glyph;
5395 static const char* get_opentype_script(const GdiFont *font)
5398 * I am not sure if this is the correct way to generate our script tag
5401 switch (font->charset)
5403 case ANSI_CHARSET: return "latn";
5404 case BALTIC_CHARSET: return "latn"; /* ?? */
5405 case CHINESEBIG5_CHARSET: return "hani";
5406 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5407 case GB2312_CHARSET: return "hani";
5408 case GREEK_CHARSET: return "grek";
5409 case HANGUL_CHARSET: return "hang";
5410 case RUSSIAN_CHARSET: return "cyrl";
5411 case SHIFTJIS_CHARSET: return "kana";
5412 case TURKISH_CHARSET: return "latn"; /* ?? */
5413 case VIETNAMESE_CHARSET: return "latn";
5414 case JOHAB_CHARSET: return "latn"; /* ?? */
5415 case ARABIC_CHARSET: return "arab";
5416 case HEBREW_CHARSET: return "hebr";
5417 case THAI_CHARSET: return "thai";
5418 default: return "latn";
5422 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5424 const GSUB_Header *header;
5425 const GSUB_Script *script;
5426 const GSUB_LangSys *language;
5427 const GSUB_Feature *feature;
5429 if (!font->GSUB_Table)
5430 return glyph;
5432 header = font->GSUB_Table;
5434 script = GSUB_get_script_table(header, get_opentype_script(font));
5435 if (!script)
5437 TRACE("Script not found\n");
5438 return glyph;
5440 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5441 if (!language)
5443 TRACE("Language not found\n");
5444 return glyph;
5446 feature = GSUB_get_feature(header, language, "vrt2");
5447 if (!feature)
5448 feature = GSUB_get_feature(header, language, "vert");
5449 if (!feature)
5451 TRACE("vrt2/vert feature not found\n");
5452 return glyph;
5454 return GSUB_apply_feature(header, feature, glyph);
5457 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5459 FT_UInt glyphId;
5461 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5462 WCHAR wc = (WCHAR)glyph;
5463 BOOL default_used;
5464 BOOL *default_used_pointer;
5465 FT_UInt ret;
5466 char buf;
5467 default_used_pointer = NULL;
5468 default_used = FALSE;
5469 if (codepage_sets_default_used(font->codepage))
5470 default_used_pointer = &default_used;
5471 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5472 ret = 0;
5473 else
5474 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5475 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5476 return ret;
5479 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5481 if (glyph < 0x100) glyph += 0xf000;
5482 /* there is a number of old pre-Unicode "broken" TTFs, which
5483 do have symbols at U+00XX instead of U+f0XX */
5484 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5485 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5487 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5489 return glyphId;
5492 /*************************************************************
5493 * freetype_GetGlyphIndices
5495 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5497 struct freetype_physdev *physdev = get_freetype_dev( dev );
5498 int i;
5499 WORD default_char;
5500 BOOL got_default = FALSE;
5502 if (!physdev->font)
5504 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5505 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5508 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5510 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5511 got_default = TRUE;
5514 GDI_CheckNotLock();
5515 EnterCriticalSection( &freetype_cs );
5517 for(i = 0; i < count; i++)
5519 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5520 if (pgi[i] == 0)
5522 if (!got_default)
5524 if (FT_IS_SFNT(physdev->font->ft_face))
5526 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5527 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5529 else
5531 TEXTMETRICW textm;
5532 get_text_metrics(physdev->font, &textm);
5533 default_char = textm.tmDefaultChar;
5535 got_default = TRUE;
5537 pgi[i] = default_char;
5540 LeaveCriticalSection( &freetype_cs );
5541 return count;
5544 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5546 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5547 return !memcmp(matrix, &identity, sizeof(FMAT2));
5550 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5552 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5553 return !memcmp(matrix, &identity, sizeof(MAT2));
5556 static inline BYTE get_max_level( UINT format )
5558 switch( format )
5560 case GGO_GRAY2_BITMAP: return 4;
5561 case GGO_GRAY4_BITMAP: return 16;
5562 case GGO_GRAY8_BITMAP: return 64;
5564 return 255;
5567 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5569 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5570 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5571 const MAT2* lpmat)
5573 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5574 FT_Face ft_face = incoming_font->ft_face;
5575 GdiFont *font = incoming_font;
5576 FT_UInt glyph_index;
5577 DWORD width, height, pitch, needed = 0;
5578 FT_Bitmap ft_bitmap;
5579 FT_Error err;
5580 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5581 FT_Angle angle = 0;
5582 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5583 double widthRatio = 1.0;
5584 FT_Matrix transMat = identityMat;
5585 FT_Matrix transMatUnrotated;
5586 BOOL needsTransform = FALSE;
5587 BOOL tategaki = (font->GSUB_Table != NULL);
5588 UINT original_index;
5590 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5591 buflen, buf, lpmat);
5593 TRACE("font transform %f %f %f %f\n",
5594 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5595 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5597 if(format & GGO_GLYPH_INDEX) {
5598 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5599 original_index = glyph;
5600 format &= ~GGO_GLYPH_INDEX;
5601 } else {
5602 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5603 ft_face = font->ft_face;
5604 original_index = glyph_index;
5607 if(format & GGO_UNHINTED) {
5608 load_flags |= FT_LOAD_NO_HINTING;
5609 format &= ~GGO_UNHINTED;
5612 /* tategaki never appears to happen to lower glyph index */
5613 if (glyph_index < TATEGAKI_LOWER_BOUND )
5614 tategaki = FALSE;
5616 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5617 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5618 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5619 font->gmsize * sizeof(GM*));
5620 } else {
5621 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5622 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5624 *lpgm = FONT_GM(font,original_index)->gm;
5625 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5626 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5627 lpgm->gmCellIncX, lpgm->gmCellIncY);
5628 return 1; /* FIXME */
5632 if (!font->gm[original_index / GM_BLOCK_SIZE])
5633 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5635 /* Scaling factor */
5636 if (font->aveWidth)
5638 TEXTMETRICW tm;
5640 get_text_metrics(font, &tm);
5642 widthRatio = (double)font->aveWidth;
5643 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5645 else
5646 widthRatio = font->scale_y;
5648 /* Scaling transform */
5649 if (widthRatio != 1.0 || font->scale_y != 1.0)
5651 FT_Matrix scaleMat;
5652 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5653 scaleMat.xy = 0;
5654 scaleMat.yx = 0;
5655 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5657 pFT_Matrix_Multiply(&scaleMat, &transMat);
5658 needsTransform = TRUE;
5661 /* Slant transform */
5662 if (font->fake_italic) {
5663 FT_Matrix slantMat;
5665 slantMat.xx = (1 << 16);
5666 slantMat.xy = ((1 << 16) >> 2);
5667 slantMat.yx = 0;
5668 slantMat.yy = (1 << 16);
5669 pFT_Matrix_Multiply(&slantMat, &transMat);
5670 needsTransform = TRUE;
5673 /* Rotation transform */
5674 transMatUnrotated = transMat;
5675 if(font->orientation && !tategaki) {
5676 FT_Matrix rotationMat;
5677 FT_Vector vecAngle;
5678 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5679 pFT_Vector_Unit(&vecAngle, angle);
5680 rotationMat.xx = vecAngle.x;
5681 rotationMat.xy = -vecAngle.y;
5682 rotationMat.yx = -rotationMat.xy;
5683 rotationMat.yy = rotationMat.xx;
5685 pFT_Matrix_Multiply(&rotationMat, &transMat);
5686 needsTransform = TRUE;
5689 /* World transform */
5690 if (!is_identity_FMAT2(&font->font_desc.matrix))
5692 FT_Matrix worldMat;
5693 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5694 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5695 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5696 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5697 pFT_Matrix_Multiply(&worldMat, &transMat);
5698 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5699 needsTransform = TRUE;
5702 /* Extra transformation specified by caller */
5703 if (!is_identity_MAT2(lpmat))
5705 FT_Matrix extraMat;
5706 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5707 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5708 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5709 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5710 pFT_Matrix_Multiply(&extraMat, &transMat);
5711 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5712 needsTransform = TRUE;
5715 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5716 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5717 format == GGO_GRAY8_BITMAP))
5719 load_flags |= FT_LOAD_NO_BITMAP;
5722 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5724 if(err) {
5725 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5726 return GDI_ERROR;
5729 if(!needsTransform) {
5730 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5731 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5732 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5734 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5735 bottom = (ft_face->glyph->metrics.horiBearingY -
5736 ft_face->glyph->metrics.height) & -64;
5737 lpgm->gmCellIncX = adv;
5738 lpgm->gmCellIncY = 0;
5739 } else {
5740 INT xc, yc;
5741 FT_Vector vec;
5743 left = right = 0;
5745 for(xc = 0; xc < 2; xc++) {
5746 for(yc = 0; yc < 2; yc++) {
5747 vec.x = (ft_face->glyph->metrics.horiBearingX +
5748 xc * ft_face->glyph->metrics.width);
5749 vec.y = ft_face->glyph->metrics.horiBearingY -
5750 yc * ft_face->glyph->metrics.height;
5751 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5752 pFT_Vector_Transform(&vec, &transMat);
5753 if(xc == 0 && yc == 0) {
5754 left = right = vec.x;
5755 top = bottom = vec.y;
5756 } else {
5757 if(vec.x < left) left = vec.x;
5758 else if(vec.x > right) right = vec.x;
5759 if(vec.y < bottom) bottom = vec.y;
5760 else if(vec.y > top) top = vec.y;
5764 left = left & -64;
5765 right = (right + 63) & -64;
5766 bottom = bottom & -64;
5767 top = (top + 63) & -64;
5769 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5770 vec.x = ft_face->glyph->metrics.horiAdvance;
5771 vec.y = 0;
5772 pFT_Vector_Transform(&vec, &transMat);
5773 lpgm->gmCellIncX = (vec.x+63) >> 6;
5774 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5776 vec.x = ft_face->glyph->metrics.horiAdvance;
5777 vec.y = 0;
5778 pFT_Vector_Transform(&vec, &transMatUnrotated);
5779 adv = (vec.x+63) >> 6;
5782 lsb = left >> 6;
5783 bbx = (right - left) >> 6;
5784 lpgm->gmBlackBoxX = (right - left) >> 6;
5785 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5786 lpgm->gmptGlyphOrigin.x = left >> 6;
5787 lpgm->gmptGlyphOrigin.y = top >> 6;
5789 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5790 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5791 lpgm->gmCellIncX, lpgm->gmCellIncY);
5793 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5794 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5796 FONT_GM(font,original_index)->gm = *lpgm;
5797 FONT_GM(font,original_index)->adv = adv;
5798 FONT_GM(font,original_index)->lsb = lsb;
5799 FONT_GM(font,original_index)->bbx = bbx;
5800 FONT_GM(font,original_index)->init = TRUE;
5803 if(format == GGO_METRICS)
5805 return 1; /* FIXME */
5808 if(ft_face->glyph->format != ft_glyph_format_outline &&
5809 (format == GGO_NATIVE || format == GGO_BEZIER))
5811 TRACE("loaded a bitmap\n");
5812 return GDI_ERROR;
5815 switch(format) {
5816 case GGO_BITMAP:
5817 width = lpgm->gmBlackBoxX;
5818 height = lpgm->gmBlackBoxY;
5819 pitch = ((width + 31) >> 5) << 2;
5820 needed = pitch * height;
5822 if(!buf || !buflen) break;
5824 switch(ft_face->glyph->format) {
5825 case ft_glyph_format_bitmap:
5827 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5828 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5829 INT h = ft_face->glyph->bitmap.rows;
5830 while(h--) {
5831 memcpy(dst, src, w);
5832 src += ft_face->glyph->bitmap.pitch;
5833 dst += pitch;
5835 break;
5838 case ft_glyph_format_outline:
5839 ft_bitmap.width = width;
5840 ft_bitmap.rows = height;
5841 ft_bitmap.pitch = pitch;
5842 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5843 ft_bitmap.buffer = buf;
5845 if(needsTransform)
5846 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5848 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5850 /* Note: FreeType will only set 'black' bits for us. */
5851 memset(buf, 0, needed);
5852 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5853 break;
5855 default:
5856 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5857 return GDI_ERROR;
5859 break;
5861 case GGO_GRAY2_BITMAP:
5862 case GGO_GRAY4_BITMAP:
5863 case GGO_GRAY8_BITMAP:
5864 case WINE_GGO_GRAY16_BITMAP:
5866 unsigned int max_level, row, col;
5867 BYTE *start, *ptr;
5869 width = lpgm->gmBlackBoxX;
5870 height = lpgm->gmBlackBoxY;
5871 pitch = (width + 3) / 4 * 4;
5872 needed = pitch * height;
5874 if(!buf || !buflen) break;
5876 max_level = get_max_level( format );
5878 switch(ft_face->glyph->format) {
5879 case ft_glyph_format_bitmap:
5881 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5882 INT h = ft_face->glyph->bitmap.rows;
5883 INT x;
5884 memset( buf, 0, needed );
5885 while(h--) {
5886 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5887 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5888 src += ft_face->glyph->bitmap.pitch;
5889 dst += pitch;
5891 return needed;
5893 case ft_glyph_format_outline:
5895 ft_bitmap.width = width;
5896 ft_bitmap.rows = height;
5897 ft_bitmap.pitch = pitch;
5898 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5899 ft_bitmap.buffer = buf;
5901 if(needsTransform)
5902 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5904 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5906 memset(ft_bitmap.buffer, 0, buflen);
5908 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5910 if (max_level != 255)
5912 for (row = 0, start = buf; row < height; row++)
5914 for (col = 0, ptr = start; col < width; col++, ptr++)
5915 *ptr = (((int)*ptr) * max_level + 128) / 256;
5916 start += pitch;
5919 return needed;
5922 default:
5923 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5924 return GDI_ERROR;
5926 break;
5929 case WINE_GGO_HRGB_BITMAP:
5930 case WINE_GGO_HBGR_BITMAP:
5931 case WINE_GGO_VRGB_BITMAP:
5932 case WINE_GGO_VBGR_BITMAP:
5933 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5935 switch (ft_face->glyph->format)
5937 case FT_GLYPH_FORMAT_BITMAP:
5939 BYTE *src, *dst;
5940 INT src_pitch, x;
5942 width = lpgm->gmBlackBoxX;
5943 height = lpgm->gmBlackBoxY;
5944 pitch = width * 4;
5945 needed = pitch * height;
5947 if (!buf || !buflen) break;
5949 memset(buf, 0, buflen);
5950 dst = buf;
5951 src = ft_face->glyph->bitmap.buffer;
5952 src_pitch = ft_face->glyph->bitmap.pitch;
5954 height = min( height, ft_face->glyph->bitmap.rows );
5955 while ( height-- )
5957 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5959 if ( src[x / 8] & masks[x % 8] )
5960 ((unsigned int *)dst)[x] = ~0u;
5962 src += src_pitch;
5963 dst += pitch;
5966 break;
5969 case FT_GLYPH_FORMAT_OUTLINE:
5971 unsigned int *dst;
5972 BYTE *src;
5973 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5974 INT x_shift, y_shift;
5975 BOOL rgb;
5976 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5977 FT_Render_Mode render_mode =
5978 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5979 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5981 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5983 if ( render_mode == FT_RENDER_MODE_LCD)
5985 lpgm->gmBlackBoxX += 2;
5986 lpgm->gmptGlyphOrigin.x -= 1;
5988 else
5990 lpgm->gmBlackBoxY += 2;
5991 lpgm->gmptGlyphOrigin.y += 1;
5995 width = lpgm->gmBlackBoxX;
5996 height = lpgm->gmBlackBoxY;
5997 pitch = width * 4;
5998 needed = pitch * height;
6000 if (!buf || !buflen) break;
6002 memset(buf, 0, buflen);
6003 dst = buf;
6004 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6006 if ( needsTransform )
6007 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6009 if ( pFT_Library_SetLcdFilter )
6010 pFT_Library_SetLcdFilter( library, lcdfilter );
6011 pFT_Render_Glyph (ft_face->glyph, render_mode);
6013 src = ft_face->glyph->bitmap.buffer;
6014 src_pitch = ft_face->glyph->bitmap.pitch;
6015 src_width = ft_face->glyph->bitmap.width;
6016 src_height = ft_face->glyph->bitmap.rows;
6018 if ( render_mode == FT_RENDER_MODE_LCD)
6020 rgb_interval = 1;
6021 hmul = 3;
6022 vmul = 1;
6024 else
6026 rgb_interval = src_pitch;
6027 hmul = 1;
6028 vmul = 3;
6031 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6032 if ( x_shift < 0 ) x_shift = 0;
6033 if ( x_shift + (src_width / hmul) > width )
6034 x_shift = width - (src_width / hmul);
6036 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6037 if ( y_shift < 0 ) y_shift = 0;
6038 if ( y_shift + (src_height / vmul) > height )
6039 y_shift = height - (src_height / vmul);
6041 dst += x_shift + y_shift * ( pitch / 4 );
6042 while ( src_height )
6044 for ( x = 0; x < src_width / hmul; x++ )
6046 if ( rgb )
6048 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6049 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6050 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6051 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6053 else
6055 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6056 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6057 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6058 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6061 src += src_pitch * vmul;
6062 dst += pitch / 4;
6063 src_height -= vmul;
6066 break;
6069 default:
6070 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6071 return GDI_ERROR;
6074 break;
6076 #else
6077 return GDI_ERROR;
6078 #endif
6080 case GGO_NATIVE:
6082 int contour, point = 0, first_pt;
6083 FT_Outline *outline = &ft_face->glyph->outline;
6084 TTPOLYGONHEADER *pph;
6085 TTPOLYCURVE *ppc;
6086 DWORD pph_start, cpfx, type;
6088 if(buflen == 0) buf = NULL;
6090 if (needsTransform && buf) {
6091 pFT_Outline_Transform(outline, &transMat);
6094 for(contour = 0; contour < outline->n_contours; contour++) {
6095 pph_start = needed;
6096 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6097 first_pt = point;
6098 if(buf) {
6099 pph->dwType = TT_POLYGON_TYPE;
6100 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6102 needed += sizeof(*pph);
6103 point++;
6104 while(point <= outline->contours[contour]) {
6105 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6106 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6107 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6108 cpfx = 0;
6109 do {
6110 if(buf)
6111 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6112 cpfx++;
6113 point++;
6114 } while(point <= outline->contours[contour] &&
6115 (outline->tags[point] & FT_Curve_Tag_On) ==
6116 (outline->tags[point-1] & FT_Curve_Tag_On));
6117 /* At the end of a contour Windows adds the start point, but
6118 only for Beziers */
6119 if(point > outline->contours[contour] &&
6120 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6121 if(buf)
6122 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6123 cpfx++;
6124 } else if(point <= outline->contours[contour] &&
6125 outline->tags[point] & FT_Curve_Tag_On) {
6126 /* add closing pt for bezier */
6127 if(buf)
6128 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6129 cpfx++;
6130 point++;
6132 if(buf) {
6133 ppc->wType = type;
6134 ppc->cpfx = cpfx;
6136 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6138 if(buf)
6139 pph->cb = needed - pph_start;
6141 break;
6143 case GGO_BEZIER:
6145 /* Convert the quadratic Beziers to cubic Beziers.
6146 The parametric eqn for a cubic Bezier is, from PLRM:
6147 r(t) = at^3 + bt^2 + ct + r0
6148 with the control points:
6149 r1 = r0 + c/3
6150 r2 = r1 + (c + b)/3
6151 r3 = r0 + c + b + a
6153 A quadratic Bezier has the form:
6154 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6156 So equating powers of t leads to:
6157 r1 = 2/3 p1 + 1/3 p0
6158 r2 = 2/3 p1 + 1/3 p2
6159 and of course r0 = p0, r3 = p2
6162 int contour, point = 0, first_pt;
6163 FT_Outline *outline = &ft_face->glyph->outline;
6164 TTPOLYGONHEADER *pph;
6165 TTPOLYCURVE *ppc;
6166 DWORD pph_start, cpfx, type;
6167 FT_Vector cubic_control[4];
6168 if(buflen == 0) buf = NULL;
6170 if (needsTransform && buf) {
6171 pFT_Outline_Transform(outline, &transMat);
6174 for(contour = 0; contour < outline->n_contours; contour++) {
6175 pph_start = needed;
6176 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6177 first_pt = point;
6178 if(buf) {
6179 pph->dwType = TT_POLYGON_TYPE;
6180 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6182 needed += sizeof(*pph);
6183 point++;
6184 while(point <= outline->contours[contour]) {
6185 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6186 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6187 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6188 cpfx = 0;
6189 do {
6190 if(type == TT_PRIM_LINE) {
6191 if(buf)
6192 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6193 cpfx++;
6194 point++;
6195 } else {
6196 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6197 so cpfx = 3n */
6199 /* FIXME: Possible optimization in endpoint calculation
6200 if there are two consecutive curves */
6201 cubic_control[0] = outline->points[point-1];
6202 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6203 cubic_control[0].x += outline->points[point].x + 1;
6204 cubic_control[0].y += outline->points[point].y + 1;
6205 cubic_control[0].x >>= 1;
6206 cubic_control[0].y >>= 1;
6208 if(point+1 > outline->contours[contour])
6209 cubic_control[3] = outline->points[first_pt];
6210 else {
6211 cubic_control[3] = outline->points[point+1];
6212 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6213 cubic_control[3].x += outline->points[point].x + 1;
6214 cubic_control[3].y += outline->points[point].y + 1;
6215 cubic_control[3].x >>= 1;
6216 cubic_control[3].y >>= 1;
6219 /* r1 = 1/3 p0 + 2/3 p1
6220 r2 = 1/3 p2 + 2/3 p1 */
6221 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6222 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6223 cubic_control[2] = cubic_control[1];
6224 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6225 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6226 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6227 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6228 if(buf) {
6229 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6230 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6231 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6233 cpfx += 3;
6234 point++;
6236 } while(point <= outline->contours[contour] &&
6237 (outline->tags[point] & FT_Curve_Tag_On) ==
6238 (outline->tags[point-1] & FT_Curve_Tag_On));
6239 /* At the end of a contour Windows adds the start point,
6240 but only for Beziers and we've already done that.
6242 if(point <= outline->contours[contour] &&
6243 outline->tags[point] & FT_Curve_Tag_On) {
6244 /* This is the closing pt of a bezier, but we've already
6245 added it, so just inc point and carry on */
6246 point++;
6248 if(buf) {
6249 ppc->wType = type;
6250 ppc->cpfx = cpfx;
6252 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6254 if(buf)
6255 pph->cb = needed - pph_start;
6257 break;
6260 default:
6261 FIXME("Unsupported format %d\n", format);
6262 return GDI_ERROR;
6264 return needed;
6267 static BOOL get_bitmap_text_metrics(GdiFont *font)
6269 FT_Face ft_face = font->ft_face;
6270 FT_WinFNT_HeaderRec winfnt_header;
6271 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6272 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6273 font->potm->otmSize = size;
6275 #define TM font->potm->otmTextMetrics
6276 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6278 TM.tmHeight = winfnt_header.pixel_height;
6279 TM.tmAscent = winfnt_header.ascent;
6280 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6281 TM.tmInternalLeading = winfnt_header.internal_leading;
6282 TM.tmExternalLeading = winfnt_header.external_leading;
6283 TM.tmAveCharWidth = winfnt_header.avg_width;
6284 TM.tmMaxCharWidth = winfnt_header.max_width;
6285 TM.tmWeight = winfnt_header.weight;
6286 TM.tmOverhang = 0;
6287 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6288 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6289 TM.tmFirstChar = winfnt_header.first_char;
6290 TM.tmLastChar = winfnt_header.last_char;
6291 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6292 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6293 TM.tmItalic = winfnt_header.italic;
6294 TM.tmUnderlined = font->underline;
6295 TM.tmStruckOut = font->strikeout;
6296 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6297 TM.tmCharSet = winfnt_header.charset;
6299 else
6301 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6302 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6303 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6304 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6305 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6306 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6307 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6308 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6309 TM.tmOverhang = 0;
6310 TM.tmDigitizedAspectX = 96; /* FIXME */
6311 TM.tmDigitizedAspectY = 96; /* FIXME */
6312 TM.tmFirstChar = 1;
6313 TM.tmLastChar = 255;
6314 TM.tmDefaultChar = 32;
6315 TM.tmBreakChar = 32;
6316 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6317 TM.tmUnderlined = font->underline;
6318 TM.tmStruckOut = font->strikeout;
6319 /* NB inverted meaning of TMPF_FIXED_PITCH */
6320 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6321 TM.tmCharSet = font->charset;
6323 #undef TM
6325 return TRUE;
6329 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6331 double scale_x, scale_y;
6333 if (font->aveWidth)
6335 scale_x = (double)font->aveWidth;
6336 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6338 else
6339 scale_x = font->scale_y;
6341 scale_x *= fabs(font->font_desc.matrix.eM11);
6342 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6344 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6345 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6347 SCALE_Y(ptm->tmHeight);
6348 SCALE_Y(ptm->tmAscent);
6349 SCALE_Y(ptm->tmDescent);
6350 SCALE_Y(ptm->tmInternalLeading);
6351 SCALE_Y(ptm->tmExternalLeading);
6352 SCALE_Y(ptm->tmOverhang);
6354 SCALE_X(ptm->tmAveCharWidth);
6355 SCALE_X(ptm->tmMaxCharWidth);
6357 #undef SCALE_X
6358 #undef SCALE_Y
6361 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6363 double scale_x, scale_y;
6365 if (font->aveWidth)
6367 scale_x = (double)font->aveWidth;
6368 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6370 else
6371 scale_x = font->scale_y;
6373 scale_x *= fabs(font->font_desc.matrix.eM11);
6374 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6376 scale_font_metrics(font, &potm->otmTextMetrics);
6378 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6379 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6381 SCALE_Y(potm->otmAscent);
6382 SCALE_Y(potm->otmDescent);
6383 SCALE_Y(potm->otmLineGap);
6384 SCALE_Y(potm->otmsCapEmHeight);
6385 SCALE_Y(potm->otmsXHeight);
6386 SCALE_Y(potm->otmrcFontBox.top);
6387 SCALE_Y(potm->otmrcFontBox.bottom);
6388 SCALE_X(potm->otmrcFontBox.left);
6389 SCALE_X(potm->otmrcFontBox.right);
6390 SCALE_Y(potm->otmMacAscent);
6391 SCALE_Y(potm->otmMacDescent);
6392 SCALE_Y(potm->otmMacLineGap);
6393 SCALE_X(potm->otmptSubscriptSize.x);
6394 SCALE_Y(potm->otmptSubscriptSize.y);
6395 SCALE_X(potm->otmptSubscriptOffset.x);
6396 SCALE_Y(potm->otmptSubscriptOffset.y);
6397 SCALE_X(potm->otmptSuperscriptSize.x);
6398 SCALE_Y(potm->otmptSuperscriptSize.y);
6399 SCALE_X(potm->otmptSuperscriptOffset.x);
6400 SCALE_Y(potm->otmptSuperscriptOffset.y);
6401 SCALE_Y(potm->otmsStrikeoutSize);
6402 SCALE_Y(potm->otmsStrikeoutPosition);
6403 SCALE_Y(potm->otmsUnderscoreSize);
6404 SCALE_Y(potm->otmsUnderscorePosition);
6406 #undef SCALE_X
6407 #undef SCALE_Y
6410 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6412 if(!font->potm)
6414 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6416 /* Make sure that the font has sane width/height ratio */
6417 if (font->aveWidth)
6419 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6421 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6422 font->aveWidth = 0;
6426 *ptm = font->potm->otmTextMetrics;
6427 scale_font_metrics(font, ptm);
6428 return TRUE;
6431 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6433 int i;
6435 for(i = 0; i < ft_face->num_charmaps; i++)
6437 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6438 return TRUE;
6440 return FALSE;
6443 static BOOL get_outline_text_metrics(GdiFont *font)
6445 BOOL ret = FALSE;
6446 FT_Face ft_face = font->ft_face;
6447 UINT needed, lenfam, lensty;
6448 TT_OS2 *pOS2;
6449 TT_HoriHeader *pHori;
6450 TT_Postscript *pPost;
6451 FT_Fixed x_scale, y_scale;
6452 WCHAR *family_nameW, *style_nameW;
6453 static const WCHAR spaceW[] = {' ', '\0'};
6454 char *cp;
6455 INT ascent, descent;
6457 TRACE("font=%p\n", font);
6459 if(!FT_IS_SCALABLE(ft_face))
6460 return FALSE;
6462 needed = sizeof(*font->potm);
6464 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6465 family_nameW = strdupW(font->name);
6467 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6468 * sizeof(WCHAR);
6469 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6470 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6471 style_nameW, lensty/sizeof(WCHAR));
6473 /* These names should be read from the TT name table */
6475 /* length of otmpFamilyName */
6476 needed += lenfam;
6478 /* length of otmpFaceName */
6479 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6480 needed += lenfam; /* just the family name */
6481 } else {
6482 needed += lenfam + lensty; /* family + " " + style */
6485 /* length of otmpStyleName */
6486 needed += lensty;
6488 /* length of otmpFullName */
6489 needed += lenfam + lensty;
6492 x_scale = ft_face->size->metrics.x_scale;
6493 y_scale = ft_face->size->metrics.y_scale;
6495 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6496 if(!pOS2) {
6497 FIXME("Can't find OS/2 table - not TT font?\n");
6498 goto end;
6501 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6502 if(!pHori) {
6503 FIXME("Can't find HHEA table - not TT font?\n");
6504 goto end;
6507 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6509 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",
6510 pOS2->usWinAscent, pOS2->usWinDescent,
6511 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6512 ft_face->ascender, ft_face->descender, ft_face->height,
6513 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6514 ft_face->bbox.yMax, ft_face->bbox.yMin);
6516 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6517 font->potm->otmSize = needed;
6519 #define TM font->potm->otmTextMetrics
6521 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6522 ascent = pHori->Ascender;
6523 descent = -pHori->Descender;
6524 } else {
6525 ascent = pOS2->usWinAscent;
6526 descent = pOS2->usWinDescent;
6529 if(font->yMax) {
6530 TM.tmAscent = font->yMax;
6531 TM.tmDescent = -font->yMin;
6532 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6533 } else {
6534 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6535 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6536 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6537 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6540 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6542 /* MSDN says:
6543 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6545 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6546 ((ascent + descent) -
6547 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6549 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6550 if (TM.tmAveCharWidth == 0) {
6551 TM.tmAveCharWidth = 1;
6553 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6554 TM.tmWeight = FW_REGULAR;
6555 if (font->fake_bold)
6556 TM.tmWeight = FW_BOLD;
6557 else
6559 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6561 if (pOS2->usWeightClass > FW_MEDIUM)
6562 TM.tmWeight = pOS2->usWeightClass;
6564 else if (pOS2->usWeightClass <= FW_MEDIUM)
6565 TM.tmWeight = pOS2->usWeightClass;
6567 TM.tmOverhang = 0;
6568 TM.tmDigitizedAspectX = 300;
6569 TM.tmDigitizedAspectY = 300;
6570 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6571 * symbol range to 0 - f0ff
6574 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6576 TM.tmFirstChar = 0;
6577 switch(GetACP())
6579 case 1257: /* Baltic */
6580 TM.tmLastChar = 0xf8fd;
6581 break;
6582 default:
6583 TM.tmLastChar = 0xf0ff;
6585 TM.tmBreakChar = 0x20;
6586 TM.tmDefaultChar = 0x1f;
6588 else
6590 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6591 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6593 if(pOS2->usFirstCharIndex <= 1)
6594 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6595 else if (pOS2->usFirstCharIndex > 0xff)
6596 TM.tmBreakChar = 0x20;
6597 else
6598 TM.tmBreakChar = pOS2->usFirstCharIndex;
6599 TM.tmDefaultChar = TM.tmBreakChar - 1;
6601 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6602 TM.tmUnderlined = font->underline;
6603 TM.tmStruckOut = font->strikeout;
6605 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6606 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6607 (pOS2->version == 0xFFFFU ||
6608 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6609 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6610 else
6611 TM.tmPitchAndFamily = 0;
6613 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6615 case PAN_FAMILY_SCRIPT:
6616 TM.tmPitchAndFamily |= FF_SCRIPT;
6617 break;
6619 case PAN_FAMILY_DECORATIVE:
6620 TM.tmPitchAndFamily |= FF_DECORATIVE;
6621 break;
6623 case PAN_ANY:
6624 case PAN_NO_FIT:
6625 case PAN_FAMILY_TEXT_DISPLAY:
6626 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6627 /* which is clearly not what the panose spec says. */
6628 default:
6629 if(TM.tmPitchAndFamily == 0 || /* fixed */
6630 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6631 TM.tmPitchAndFamily = FF_MODERN;
6632 else
6634 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6636 case PAN_ANY:
6637 case PAN_NO_FIT:
6638 default:
6639 TM.tmPitchAndFamily |= FF_DONTCARE;
6640 break;
6642 case PAN_SERIF_COVE:
6643 case PAN_SERIF_OBTUSE_COVE:
6644 case PAN_SERIF_SQUARE_COVE:
6645 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6646 case PAN_SERIF_SQUARE:
6647 case PAN_SERIF_THIN:
6648 case PAN_SERIF_BONE:
6649 case PAN_SERIF_EXAGGERATED:
6650 case PAN_SERIF_TRIANGLE:
6651 TM.tmPitchAndFamily |= FF_ROMAN;
6652 break;
6654 case PAN_SERIF_NORMAL_SANS:
6655 case PAN_SERIF_OBTUSE_SANS:
6656 case PAN_SERIF_PERP_SANS:
6657 case PAN_SERIF_FLARED:
6658 case PAN_SERIF_ROUNDED:
6659 TM.tmPitchAndFamily |= FF_SWISS;
6660 break;
6663 break;
6666 if(FT_IS_SCALABLE(ft_face))
6667 TM.tmPitchAndFamily |= TMPF_VECTOR;
6669 if(FT_IS_SFNT(ft_face))
6671 if (font->ntmFlags & NTM_PS_OPENTYPE)
6672 TM.tmPitchAndFamily |= TMPF_DEVICE;
6673 else
6674 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6677 TM.tmCharSet = font->charset;
6679 font->potm->otmFiller = 0;
6680 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6681 font->potm->otmfsSelection = pOS2->fsSelection;
6682 font->potm->otmfsType = pOS2->fsType;
6683 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6684 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6685 font->potm->otmItalicAngle = 0; /* POST table */
6686 font->potm->otmEMSquare = ft_face->units_per_EM;
6687 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6688 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6689 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6690 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6691 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6692 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6693 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6694 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6695 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6696 font->potm->otmMacAscent = TM.tmAscent;
6697 font->potm->otmMacDescent = -TM.tmDescent;
6698 font->potm->otmMacLineGap = font->potm->otmLineGap;
6699 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6700 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6701 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6702 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6703 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6704 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6705 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6706 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6707 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6708 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6709 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6710 if(!pPost) {
6711 font->potm->otmsUnderscoreSize = 0;
6712 font->potm->otmsUnderscorePosition = 0;
6713 } else {
6714 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6715 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6717 #undef TM
6719 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6720 cp = (char*)font->potm + sizeof(*font->potm);
6721 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6722 strcpyW((WCHAR*)cp, family_nameW);
6723 cp += lenfam;
6724 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6725 strcpyW((WCHAR*)cp, style_nameW);
6726 cp += lensty;
6727 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6728 strcpyW((WCHAR*)cp, family_nameW);
6729 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6730 strcatW((WCHAR*)cp, spaceW);
6731 strcatW((WCHAR*)cp, style_nameW);
6732 cp += lenfam + lensty;
6733 } else
6734 cp += lenfam;
6735 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6736 strcpyW((WCHAR*)cp, family_nameW);
6737 strcatW((WCHAR*)cp, spaceW);
6738 strcatW((WCHAR*)cp, style_nameW);
6739 ret = TRUE;
6741 end:
6742 HeapFree(GetProcessHeap(), 0, style_nameW);
6743 HeapFree(GetProcessHeap(), 0, family_nameW);
6744 return ret;
6747 /*************************************************************
6748 * freetype_GetGlyphOutline
6750 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6751 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6753 struct freetype_physdev *physdev = get_freetype_dev( dev );
6754 DWORD ret;
6756 if (!physdev->font)
6758 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6759 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6762 GDI_CheckNotLock();
6763 EnterCriticalSection( &freetype_cs );
6764 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6765 LeaveCriticalSection( &freetype_cs );
6766 return ret;
6769 /*************************************************************
6770 * freetype_GetTextMetrics
6772 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6774 struct freetype_physdev *physdev = get_freetype_dev( dev );
6775 BOOL ret;
6777 if (!physdev->font)
6779 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6780 return dev->funcs->pGetTextMetrics( dev, metrics );
6783 GDI_CheckNotLock();
6784 EnterCriticalSection( &freetype_cs );
6785 ret = get_text_metrics( physdev->font, metrics );
6786 LeaveCriticalSection( &freetype_cs );
6787 return ret;
6790 /*************************************************************
6791 * freetype_GetOutlineTextMetrics
6793 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6795 struct freetype_physdev *physdev = get_freetype_dev( dev );
6796 UINT ret = 0;
6798 if (!physdev->font)
6800 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6801 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6804 TRACE("font=%p\n", physdev->font);
6806 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6808 GDI_CheckNotLock();
6809 EnterCriticalSection( &freetype_cs );
6811 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6813 if(cbSize >= physdev->font->potm->otmSize)
6815 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6816 scale_outline_font_metrics(physdev->font, potm);
6818 ret = physdev->font->potm->otmSize;
6820 LeaveCriticalSection( &freetype_cs );
6821 return ret;
6824 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6826 HFONTLIST *hfontlist;
6827 child->font = alloc_font();
6828 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6829 if(!child->font->ft_face)
6831 free_font(child->font);
6832 child->font = NULL;
6833 return FALSE;
6836 child->font->font_desc = font->font_desc;
6837 child->font->ntmFlags = child->face->ntmFlags;
6838 child->font->orientation = font->orientation;
6839 child->font->scale_y = font->scale_y;
6840 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6841 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6842 child->font->name = strdupW(child->face->family->FamilyName);
6843 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6844 child->font->base_font = font;
6845 list_add_head(&child_font_list, &child->font->entry);
6846 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6847 return TRUE;
6850 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6852 FT_UInt g;
6853 CHILD_FONT *child_font;
6855 if(font->base_font)
6856 font = font->base_font;
6858 *linked_font = font;
6860 if((*glyph = get_glyph_index(font, c)))
6862 *glyph = get_GSUB_vert_glyph(font, *glyph);
6863 return TRUE;
6866 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6868 if(!child_font->font)
6869 if(!load_child_font(font, child_font))
6870 continue;
6872 if(!child_font->font->ft_face)
6873 continue;
6874 g = get_glyph_index(child_font->font, c);
6875 g = get_GSUB_vert_glyph(child_font->font, g);
6876 if(g)
6878 *glyph = g;
6879 *linked_font = child_font->font;
6880 return TRUE;
6883 return FALSE;
6886 /*************************************************************
6887 * freetype_GetCharWidth
6889 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6891 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6892 UINT c;
6893 GLYPHMETRICS gm;
6894 FT_UInt glyph_index;
6895 GdiFont *linked_font;
6896 struct freetype_physdev *physdev = get_freetype_dev( dev );
6898 if (!physdev->font)
6900 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6901 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6904 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6906 GDI_CheckNotLock();
6907 EnterCriticalSection( &freetype_cs );
6908 for(c = firstChar; c <= lastChar; c++) {
6909 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6910 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6911 &gm, 0, NULL, &identity);
6912 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6914 LeaveCriticalSection( &freetype_cs );
6915 return TRUE;
6918 /*************************************************************
6919 * freetype_GetCharABCWidths
6921 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6923 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6924 UINT c;
6925 GLYPHMETRICS gm;
6926 FT_UInt glyph_index;
6927 GdiFont *linked_font;
6928 struct freetype_physdev *physdev = get_freetype_dev( dev );
6930 if (!physdev->font)
6932 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6933 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6936 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6938 GDI_CheckNotLock();
6939 EnterCriticalSection( &freetype_cs );
6941 for(c = firstChar; c <= lastChar; c++) {
6942 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6943 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6944 &gm, 0, NULL, &identity);
6945 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6946 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6947 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6948 FONT_GM(linked_font,glyph_index)->bbx;
6950 LeaveCriticalSection( &freetype_cs );
6951 return TRUE;
6954 /*************************************************************
6955 * freetype_GetCharABCWidthsI
6957 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6959 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6960 UINT c;
6961 GLYPHMETRICS gm;
6962 FT_UInt glyph_index;
6963 GdiFont *linked_font;
6964 struct freetype_physdev *physdev = get_freetype_dev( dev );
6966 if (!physdev->font)
6968 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6969 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6972 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6973 return FALSE;
6975 GDI_CheckNotLock();
6976 EnterCriticalSection( &freetype_cs );
6978 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6979 if (!pgi)
6980 for(c = firstChar; c < firstChar+count; c++) {
6981 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6982 &gm, 0, NULL, &identity);
6983 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6984 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6985 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6986 - FONT_GM(linked_font,c)->bbx;
6988 else
6989 for(c = 0; c < count; c++) {
6990 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6991 &gm, 0, NULL, &identity);
6992 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6993 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6994 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6995 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6998 LeaveCriticalSection( &freetype_cs );
6999 return TRUE;
7002 /*************************************************************
7003 * freetype_GetTextExtentExPoint
7005 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7006 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7008 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7009 INT idx;
7010 INT nfit = 0, ext;
7011 GLYPHMETRICS gm;
7012 TEXTMETRICW tm;
7013 FT_UInt glyph_index;
7014 GdiFont *linked_font;
7015 struct freetype_physdev *physdev = get_freetype_dev( dev );
7017 if (!physdev->font)
7019 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7020 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7023 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7025 GDI_CheckNotLock();
7026 EnterCriticalSection( &freetype_cs );
7028 size->cx = 0;
7029 get_text_metrics( physdev->font, &tm );
7030 size->cy = tm.tmHeight;
7032 for(idx = 0; idx < count; idx++) {
7033 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7034 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7035 &gm, 0, NULL, &identity);
7036 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7037 ext = size->cx;
7038 if (! pnfit || ext <= max_ext) {
7039 ++nfit;
7040 if (dxs)
7041 dxs[idx] = ext;
7045 if (pnfit)
7046 *pnfit = nfit;
7048 LeaveCriticalSection( &freetype_cs );
7049 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7050 return TRUE;
7053 /*************************************************************
7054 * freetype_GetTextExtentExPointI
7056 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7057 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7059 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7060 INT idx;
7061 INT nfit = 0, ext;
7062 GLYPHMETRICS gm;
7063 TEXTMETRICW tm;
7064 struct freetype_physdev *physdev = get_freetype_dev( dev );
7066 if (!physdev->font)
7068 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7069 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7072 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7074 GDI_CheckNotLock();
7075 EnterCriticalSection( &freetype_cs );
7077 size->cx = 0;
7078 get_text_metrics(physdev->font, &tm);
7079 size->cy = tm.tmHeight;
7081 for(idx = 0; idx < count; idx++) {
7082 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7083 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7084 ext = size->cx;
7085 if (! pnfit || ext <= max_ext) {
7086 ++nfit;
7087 if (dxs)
7088 dxs[idx] = ext;
7092 if (pnfit)
7093 *pnfit = nfit;
7095 LeaveCriticalSection( &freetype_cs );
7096 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7097 return TRUE;
7100 /*************************************************************
7101 * freetype_GetFontData
7103 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7105 struct freetype_physdev *physdev = get_freetype_dev( dev );
7107 if (!physdev->font)
7109 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7110 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7113 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7114 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7115 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7117 return get_font_data( physdev->font, table, offset, buf, cbData );
7120 /*************************************************************
7121 * freetype_GetTextFace
7123 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7125 INT n;
7126 struct freetype_physdev *physdev = get_freetype_dev( dev );
7128 if (!physdev->font)
7130 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7131 return dev->funcs->pGetTextFace( dev, count, str );
7134 n = strlenW(physdev->font->name) + 1;
7135 if (str)
7137 lstrcpynW(str, physdev->font->name, count);
7138 n = min(count, n);
7140 return n;
7143 /*************************************************************
7144 * freetype_GetTextCharsetInfo
7146 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7148 struct freetype_physdev *physdev = get_freetype_dev( dev );
7150 if (!physdev->font)
7152 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7153 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7155 if (fs) *fs = physdev->font->fs;
7156 return physdev->font->charset;
7159 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7161 GdiFont *font = dc->gdiFont, *linked_font;
7162 struct list *first_hfont;
7163 BOOL ret;
7165 GDI_CheckNotLock();
7166 EnterCriticalSection( &freetype_cs );
7167 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7168 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7169 if(font == linked_font)
7170 *new_hfont = dc->hFont;
7171 else
7173 first_hfont = list_head(&linked_font->hfontlist);
7174 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7176 LeaveCriticalSection( &freetype_cs );
7177 return ret;
7180 /* Retrieve a list of supported Unicode ranges for a given font.
7181 * Can be called with NULL gs to calculate the buffer size. Returns
7182 * the number of ranges found.
7184 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7186 DWORD num_ranges = 0;
7188 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7190 FT_UInt glyph_code;
7191 FT_ULong char_code, char_code_prev;
7193 glyph_code = 0;
7194 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7196 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7197 face->num_glyphs, glyph_code, char_code);
7199 if (!glyph_code) return 0;
7201 if (gs)
7203 gs->ranges[0].wcLow = (USHORT)char_code;
7204 gs->ranges[0].cGlyphs = 0;
7205 gs->cGlyphsSupported = 0;
7208 num_ranges = 1;
7209 while (glyph_code)
7211 if (char_code < char_code_prev)
7213 ERR("expected increasing char code from FT_Get_Next_Char\n");
7214 return 0;
7216 if (char_code - char_code_prev > 1)
7218 num_ranges++;
7219 if (gs)
7221 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7222 gs->ranges[num_ranges - 1].cGlyphs = 1;
7223 gs->cGlyphsSupported++;
7226 else if (gs)
7228 gs->ranges[num_ranges - 1].cGlyphs++;
7229 gs->cGlyphsSupported++;
7231 char_code_prev = char_code;
7232 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7235 else
7236 FIXME("encoding %u not supported\n", face->charmap->encoding);
7238 return num_ranges;
7241 /*************************************************************
7242 * freetype_GetFontUnicodeRanges
7244 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7246 struct freetype_physdev *physdev = get_freetype_dev( dev );
7247 DWORD size, num_ranges;
7249 if (!physdev->font)
7251 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7252 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7255 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7256 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7257 if (glyphset)
7259 glyphset->cbThis = size;
7260 glyphset->cRanges = num_ranges;
7261 glyphset->flAccel = 0;
7263 return size;
7266 /*************************************************************
7267 * freetype_FontIsLinked
7269 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7271 struct freetype_physdev *physdev = get_freetype_dev( dev );
7272 BOOL ret;
7274 if (!physdev->font)
7276 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7277 return dev->funcs->pFontIsLinked( dev );
7280 GDI_CheckNotLock();
7281 EnterCriticalSection( &freetype_cs );
7282 ret = !list_empty(&physdev->font->child_fonts);
7283 LeaveCriticalSection( &freetype_cs );
7284 return ret;
7287 static BOOL is_hinting_enabled(void)
7289 /* Use the >= 2.2.0 function if available */
7290 if(pFT_Get_TrueType_Engine_Type)
7292 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7293 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7295 #ifdef FT_DRIVER_HAS_HINTER
7296 else
7298 FT_Module mod;
7300 /* otherwise if we've been compiled with < 2.2.0 headers
7301 use the internal macro */
7302 mod = pFT_Get_Module(library, "truetype");
7303 if(mod && FT_DRIVER_HAS_HINTER(mod))
7304 return TRUE;
7306 #endif
7308 return FALSE;
7311 static BOOL is_subpixel_rendering_enabled( void )
7313 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7314 return pFT_Library_SetLcdFilter &&
7315 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7316 #else
7317 return FALSE;
7318 #endif
7321 /*************************************************************************
7322 * GetRasterizerCaps (GDI32.@)
7324 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7326 static int hinting = -1;
7327 static int subpixel = -1;
7329 if(hinting == -1)
7331 hinting = is_hinting_enabled();
7332 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7335 if ( subpixel == -1 )
7337 subpixel = is_subpixel_rendering_enabled();
7338 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7341 lprs->nSize = sizeof(RASTERIZER_STATUS);
7342 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7343 if ( subpixel )
7344 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7345 lprs->nLanguageID = 0;
7346 return TRUE;
7349 /*************************************************************
7350 * freetype_GdiRealizationInfo
7352 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7354 struct freetype_physdev *physdev = get_freetype_dev( dev );
7355 realization_info_t *info = ptr;
7357 if (!physdev->font)
7359 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7360 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7363 FIXME("(%p, %p): stub!\n", physdev->font, info);
7365 info->flags = 1;
7366 if(FT_IS_SCALABLE(physdev->font->ft_face))
7367 info->flags |= 2;
7369 info->cache_num = physdev->font->cache_num;
7370 info->unknown2 = -1;
7371 return TRUE;
7374 /*************************************************************************
7375 * Kerning support for TrueType fonts
7377 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7379 struct TT_kern_table
7381 USHORT version;
7382 USHORT nTables;
7385 struct TT_kern_subtable
7387 USHORT version;
7388 USHORT length;
7389 union
7391 USHORT word;
7392 struct
7394 USHORT horizontal : 1;
7395 USHORT minimum : 1;
7396 USHORT cross_stream: 1;
7397 USHORT override : 1;
7398 USHORT reserved1 : 4;
7399 USHORT format : 8;
7400 } bits;
7401 } coverage;
7404 struct TT_format0_kern_subtable
7406 USHORT nPairs;
7407 USHORT searchRange;
7408 USHORT entrySelector;
7409 USHORT rangeShift;
7412 struct TT_kern_pair
7414 USHORT left;
7415 USHORT right;
7416 short value;
7419 static DWORD parse_format0_kern_subtable(GdiFont *font,
7420 const struct TT_format0_kern_subtable *tt_f0_ks,
7421 const USHORT *glyph_to_char,
7422 KERNINGPAIR *kern_pair, DWORD cPairs)
7424 USHORT i, nPairs;
7425 const struct TT_kern_pair *tt_kern_pair;
7427 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7429 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7431 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7432 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7433 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7435 if (!kern_pair || !cPairs)
7436 return nPairs;
7438 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7440 nPairs = min(nPairs, cPairs);
7442 for (i = 0; i < nPairs; i++)
7444 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7445 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7446 /* this algorithm appears to better match what Windows does */
7447 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7448 if (kern_pair->iKernAmount < 0)
7450 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7451 kern_pair->iKernAmount -= font->ppem;
7453 else if (kern_pair->iKernAmount > 0)
7455 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7456 kern_pair->iKernAmount += font->ppem;
7458 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7460 TRACE("left %u right %u value %d\n",
7461 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7463 kern_pair++;
7465 TRACE("copied %u entries\n", nPairs);
7466 return nPairs;
7469 /*************************************************************
7470 * freetype_GetKerningPairs
7472 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7474 DWORD length;
7475 void *buf;
7476 const struct TT_kern_table *tt_kern_table;
7477 const struct TT_kern_subtable *tt_kern_subtable;
7478 USHORT i, nTables;
7479 USHORT *glyph_to_char;
7480 GdiFont *font;
7481 struct freetype_physdev *physdev = get_freetype_dev( dev );
7483 if (!(font = physdev->font))
7485 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7486 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7489 GDI_CheckNotLock();
7490 EnterCriticalSection( &freetype_cs );
7491 if (font->total_kern_pairs != (DWORD)-1)
7493 if (cPairs && kern_pair)
7495 cPairs = min(cPairs, font->total_kern_pairs);
7496 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7498 else cPairs = font->total_kern_pairs;
7500 LeaveCriticalSection( &freetype_cs );
7501 return cPairs;
7504 font->total_kern_pairs = 0;
7506 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7508 if (length == GDI_ERROR)
7510 TRACE("no kerning data in the font\n");
7511 LeaveCriticalSection( &freetype_cs );
7512 return 0;
7515 buf = HeapAlloc(GetProcessHeap(), 0, length);
7516 if (!buf)
7518 WARN("Out of memory\n");
7519 LeaveCriticalSection( &freetype_cs );
7520 return 0;
7523 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7525 /* build a glyph index to char code map */
7526 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7527 if (!glyph_to_char)
7529 WARN("Out of memory allocating a glyph index to char code map\n");
7530 HeapFree(GetProcessHeap(), 0, buf);
7531 LeaveCriticalSection( &freetype_cs );
7532 return 0;
7535 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7537 FT_UInt glyph_code;
7538 FT_ULong char_code;
7540 glyph_code = 0;
7541 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7543 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7544 font->ft_face->num_glyphs, glyph_code, char_code);
7546 while (glyph_code)
7548 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7550 /* FIXME: This doesn't match what Windows does: it does some fancy
7551 * things with duplicate glyph index to char code mappings, while
7552 * we just avoid overriding existing entries.
7554 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7555 glyph_to_char[glyph_code] = (USHORT)char_code;
7557 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7560 else
7562 ULONG n;
7564 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7565 for (n = 0; n <= 65535; n++)
7566 glyph_to_char[n] = (USHORT)n;
7569 tt_kern_table = buf;
7570 nTables = GET_BE_WORD(tt_kern_table->nTables);
7571 TRACE("version %u, nTables %u\n",
7572 GET_BE_WORD(tt_kern_table->version), nTables);
7574 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7576 for (i = 0; i < nTables; i++)
7578 struct TT_kern_subtable tt_kern_subtable_copy;
7580 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7581 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7582 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7584 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7585 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7586 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7588 /* According to the TrueType specification this is the only format
7589 * that will be properly interpreted by Windows and OS/2
7591 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7593 DWORD new_chunk, old_total = font->total_kern_pairs;
7595 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7596 glyph_to_char, NULL, 0);
7597 font->total_kern_pairs += new_chunk;
7599 if (!font->kern_pairs)
7600 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7601 font->total_kern_pairs * sizeof(*font->kern_pairs));
7602 else
7603 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7604 font->total_kern_pairs * sizeof(*font->kern_pairs));
7606 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7607 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7609 else
7610 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7612 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7615 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7616 HeapFree(GetProcessHeap(), 0, buf);
7618 if (cPairs && kern_pair)
7620 cPairs = min(cPairs, font->total_kern_pairs);
7621 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7623 else cPairs = font->total_kern_pairs;
7625 LeaveCriticalSection( &freetype_cs );
7626 return cPairs;
7629 static const struct gdi_dc_funcs freetype_funcs =
7631 NULL, /* pAbortDoc */
7632 NULL, /* pAbortPath */
7633 NULL, /* pAlphaBlend */
7634 NULL, /* pAngleArc */
7635 NULL, /* pArc */
7636 NULL, /* pArcTo */
7637 NULL, /* pBeginPath */
7638 NULL, /* pBlendImage */
7639 NULL, /* pChoosePixelFormat */
7640 NULL, /* pChord */
7641 NULL, /* pCloseFigure */
7642 NULL, /* pCopyBitmap */
7643 NULL, /* pCreateBitmap */
7644 NULL, /* pCreateCompatibleDC */
7645 freetype_CreateDC, /* pCreateDC */
7646 NULL, /* pDeleteBitmap */
7647 freetype_DeleteDC, /* pDeleteDC */
7648 NULL, /* pDeleteObject */
7649 NULL, /* pDescribePixelFormat */
7650 NULL, /* pDeviceCapabilities */
7651 NULL, /* pEllipse */
7652 NULL, /* pEndDoc */
7653 NULL, /* pEndPage */
7654 NULL, /* pEndPath */
7655 freetype_EnumFonts, /* pEnumFonts */
7656 NULL, /* pEnumICMProfiles */
7657 NULL, /* pExcludeClipRect */
7658 NULL, /* pExtDeviceMode */
7659 NULL, /* pExtEscape */
7660 NULL, /* pExtFloodFill */
7661 NULL, /* pExtSelectClipRgn */
7662 NULL, /* pExtTextOut */
7663 NULL, /* pFillPath */
7664 NULL, /* pFillRgn */
7665 NULL, /* pFlattenPath */
7666 freetype_FontIsLinked, /* pFontIsLinked */
7667 NULL, /* pFrameRgn */
7668 NULL, /* pGdiComment */
7669 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7670 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7671 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7672 freetype_GetCharWidth, /* pGetCharWidth */
7673 NULL, /* pGetDeviceCaps */
7674 NULL, /* pGetDeviceGammaRamp */
7675 freetype_GetFontData, /* pGetFontData */
7676 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7677 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7678 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7679 NULL, /* pGetICMProfile */
7680 NULL, /* pGetImage */
7681 freetype_GetKerningPairs, /* pGetKerningPairs */
7682 NULL, /* pGetNearestColor */
7683 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7684 NULL, /* pGetPixel */
7685 NULL, /* pGetPixelFormat */
7686 NULL, /* pGetSystemPaletteEntries */
7687 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7688 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7689 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7690 freetype_GetTextFace, /* pGetTextFace */
7691 freetype_GetTextMetrics, /* pGetTextMetrics */
7692 NULL, /* pGradientFill */
7693 NULL, /* pIntersectClipRect */
7694 NULL, /* pInvertRgn */
7695 NULL, /* pLineTo */
7696 NULL, /* pModifyWorldTransform */
7697 NULL, /* pMoveTo */
7698 NULL, /* pOffsetClipRgn */
7699 NULL, /* pOffsetViewportOrg */
7700 NULL, /* pOffsetWindowOrg */
7701 NULL, /* pPaintRgn */
7702 NULL, /* pPatBlt */
7703 NULL, /* pPie */
7704 NULL, /* pPolyBezier */
7705 NULL, /* pPolyBezierTo */
7706 NULL, /* pPolyDraw */
7707 NULL, /* pPolyPolygon */
7708 NULL, /* pPolyPolyline */
7709 NULL, /* pPolygon */
7710 NULL, /* pPolyline */
7711 NULL, /* pPolylineTo */
7712 NULL, /* pPutImage */
7713 NULL, /* pRealizeDefaultPalette */
7714 NULL, /* pRealizePalette */
7715 NULL, /* pRectangle */
7716 NULL, /* pResetDC */
7717 NULL, /* pRestoreDC */
7718 NULL, /* pRoundRect */
7719 NULL, /* pSaveDC */
7720 NULL, /* pScaleViewportExt */
7721 NULL, /* pScaleWindowExt */
7722 NULL, /* pSelectBitmap */
7723 NULL, /* pSelectBrush */
7724 NULL, /* pSelectClipPath */
7725 freetype_SelectFont, /* pSelectFont */
7726 NULL, /* pSelectPalette */
7727 NULL, /* pSelectPen */
7728 NULL, /* pSetArcDirection */
7729 NULL, /* pSetBkColor */
7730 NULL, /* pSetBkMode */
7731 NULL, /* pSetDCBrushColor */
7732 NULL, /* pSetDCPenColor */
7733 NULL, /* pSetDIBColorTable */
7734 NULL, /* pSetDIBitsToDevice */
7735 NULL, /* pSetDeviceClipping */
7736 NULL, /* pSetDeviceGammaRamp */
7737 NULL, /* pSetLayout */
7738 NULL, /* pSetMapMode */
7739 NULL, /* pSetMapperFlags */
7740 NULL, /* pSetPixel */
7741 NULL, /* pSetPixelFormat */
7742 NULL, /* pSetPolyFillMode */
7743 NULL, /* pSetROP2 */
7744 NULL, /* pSetRelAbs */
7745 NULL, /* pSetStretchBltMode */
7746 NULL, /* pSetTextAlign */
7747 NULL, /* pSetTextCharacterExtra */
7748 NULL, /* pSetTextColor */
7749 NULL, /* pSetTextJustification */
7750 NULL, /* pSetViewportExt */
7751 NULL, /* pSetViewportOrg */
7752 NULL, /* pSetWindowExt */
7753 NULL, /* pSetWindowOrg */
7754 NULL, /* pSetWorldTransform */
7755 NULL, /* pStartDoc */
7756 NULL, /* pStartPage */
7757 NULL, /* pStretchBlt */
7758 NULL, /* pStretchDIBits */
7759 NULL, /* pStrokeAndFillPath */
7760 NULL, /* pStrokePath */
7761 NULL, /* pSwapBuffers */
7762 NULL, /* pUnrealizePalette */
7763 NULL, /* pWidenPath */
7764 /* OpenGL not supported */
7767 #else /* HAVE_FREETYPE */
7769 /*************************************************************************/
7771 BOOL WineEngInit(void)
7773 return FALSE;
7775 BOOL WineEngDestroyFontInstance(HFONT hfont)
7777 return FALSE;
7780 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7782 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7783 return 1;
7786 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7788 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7789 return TRUE;
7792 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7794 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7795 return NULL;
7798 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7799 LPCWSTR font_file, LPCWSTR font_path )
7801 FIXME("stub\n");
7802 return FALSE;
7805 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7807 return FALSE;
7810 /*************************************************************************
7811 * GetRasterizerCaps (GDI32.@)
7813 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7815 lprs->nSize = sizeof(RASTERIZER_STATUS);
7816 lprs->wFlags = 0;
7817 lprs->nLanguageID = 0;
7818 return TRUE;
7821 #endif /* HAVE_FREETYPE */