gdi32: Require that we have freetype's FT_Load_Sfnt_Table function and remove the...
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob93577667ec052816e14bf26d5b63542cf114de68
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 WINE_DEFAULT_DEBUG_CHANNEL(font);
94 #ifdef HAVE_FREETYPE
96 #ifdef HAVE_FT2BUILD_H
97 #include <ft2build.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
101 #endif
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
104 #endif
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
110 #endif
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
113 #endif
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
116 #endif
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
119 #endif
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
122 #endif
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
134 #endif
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 typedef enum
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
143 #endif
145 static FT_Library library = 0;
146 typedef struct
148 FT_Int major;
149 FT_Int minor;
150 FT_Int patch;
151 } FT_Version_t;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
170 #else
171 MAKE_FUNCPTR(FT_MulFix);
172 #endif
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Render_Glyph);
179 MAKE_FUNCPTR(FT_Select_Charmap);
180 MAKE_FUNCPTR(FT_Set_Charmap);
181 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
182 MAKE_FUNCPTR(FT_Vector_Transform);
183 MAKE_FUNCPTR(FT_Vector_Unit);
184 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
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
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
193 #endif
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
208 #endif
210 #undef MAKE_FUNCPTR
212 #ifndef FT_MAKE_TAG
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #endif
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
220 #endif
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
223 #endif
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
226 #endif
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #endif
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
233 #else
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 #endif
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
238 typedef struct {
239 FT_Short height;
240 FT_Short width;
241 FT_Pos size;
242 FT_Pos x_ppem;
243 FT_Pos y_ppem;
244 FT_Short internal_leading;
245 } Bitmap_Size;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
250 typedef struct {
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
253 } My_FT_Bitmap_Size;
255 struct enum_data
257 ENUMLOGFONTEXW elf;
258 NEWTEXTMETRICEXW ntm;
259 DWORD type;
262 typedef struct tagFace {
263 struct list entry;
264 WCHAR *StyleName;
265 WCHAR *FullName;
266 char *file;
267 void *font_data_ptr;
268 DWORD font_data_size;
269 FT_Long face_index;
270 FONTSIGNATURE fs;
271 FONTSIGNATURE fs_links;
272 DWORD ntmFlags;
273 FT_Fixed font_version;
274 BOOL scalable;
275 Bitmap_Size size; /* set if face is a bitmap */
276 BOOL external; /* TRUE if we should manually add this font to the registry */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
280 } Face;
282 typedef struct tagFamily {
283 struct list entry;
284 const WCHAR *FamilyName;
285 const WCHAR *EnglishName;
286 struct list faces;
287 } Family;
289 typedef struct {
290 GLYPHMETRICS gm;
291 INT adv; /* These three hold to widths of the unrotated chars */
292 INT lsb;
293 INT bbx;
294 BOOL init;
295 } GM;
297 typedef struct {
298 FLOAT eM11, eM12;
299 FLOAT eM21, eM22;
300 } FMAT2;
302 typedef struct {
303 DWORD hash;
304 LOGFONTW lf;
305 FMAT2 matrix;
306 BOOL can_use_bitmap;
307 } FONT_DESC;
309 typedef struct tagHFONTLIST {
310 struct list entry;
311 HFONT hfont;
312 } HFONTLIST;
314 typedef struct {
315 struct list entry;
316 Face *face;
317 GdiFont *font;
318 } CHILD_FONT;
320 struct tagGdiFont {
321 struct list entry;
322 GM **gm;
323 DWORD gmsize;
324 struct list hfontlist;
325 OUTLINETEXTMETRICW *potm;
326 DWORD total_kern_pairs;
327 KERNINGPAIR *kern_pairs;
328 struct list child_fonts;
330 /* the following members can be accessed without locking, they are never modified after creation */
331 FT_Face ft_face;
332 struct font_mapping *mapping;
333 LPWSTR name;
334 int charset;
335 int codepage;
336 BOOL fake_italic;
337 BOOL fake_bold;
338 BYTE underline;
339 BYTE strikeout;
340 INT orientation;
341 FONT_DESC font_desc;
342 LONG aveWidth, ppem;
343 double scale_y;
344 SHORT yMax;
345 SHORT yMin;
346 DWORD ntmFlags;
347 FONTSIGNATURE fs;
348 GdiFont *base_font;
349 VOID *GSUB_Table;
350 DWORD cache_num;
353 typedef struct {
354 struct list entry;
355 const WCHAR *font_name;
356 struct list links;
357 } SYSTEM_LINKS;
359 struct enum_charset_element {
360 DWORD mask;
361 DWORD charset;
362 LPCWSTR name;
365 struct enum_charset_list {
366 DWORD total;
367 struct enum_charset_element element[32];
370 #define GM_BLOCK_SIZE 128
371 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
373 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
374 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
375 #define UNUSED_CACHE_SIZE 10
376 static struct list child_font_list = LIST_INIT(child_font_list);
377 static struct list system_links = LIST_INIT(system_links);
379 static struct list font_subst_list = LIST_INIT(font_subst_list);
381 static struct list font_list = LIST_INIT(font_list);
383 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
384 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
385 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
387 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
388 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
389 'W','i','n','d','o','w','s','\\',
390 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
391 'F','o','n','t','s','\0'};
393 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
394 'W','i','n','d','o','w','s',' ','N','T','\\',
395 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
396 'F','o','n','t','s','\0'};
398 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
399 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
400 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
401 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
403 static const WCHAR * const SystemFontValues[4] = {
404 System_Value,
405 OEMFont_Value,
406 FixedSys_Value,
407 NULL
410 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
411 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
413 /* Interesting and well-known (frequently-assumed!) font names */
414 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
415 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 };
416 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
417 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
418 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
419 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
420 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
421 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
423 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
424 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
425 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
426 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
427 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
428 'E','u','r','o','p','e','a','n','\0'};
429 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
430 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
431 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
432 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
433 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
434 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
435 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
436 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
437 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
438 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
439 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
440 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
442 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
443 WesternW, /*00*/
444 Central_EuropeanW,
445 CyrillicW,
446 GreekW,
447 TurkishW,
448 HebrewW,
449 ArabicW,
450 BalticW,
451 VietnameseW, /*08*/
452 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
453 ThaiW,
454 JapaneseW,
455 CHINESE_GB2312W,
456 HangulW,
457 CHINESE_BIG5W,
458 Hangul_Johab_W,
459 NULL, NULL, /*23*/
460 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
461 SymbolW /*31*/
464 typedef struct {
465 WCHAR *name;
466 INT charset;
467 } NameCs;
469 typedef struct tagFontSubst {
470 struct list entry;
471 NameCs from;
472 NameCs to;
473 } FontSubst;
475 /* Registry font cache key and value names */
476 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
477 'F','o','n','t','s',0};
478 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
479 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
480 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
481 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
482 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
483 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
484 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
485 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
486 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
487 static const WCHAR face_size_value[] = {'S','i','z','e',0};
488 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
489 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
490 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
491 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
492 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
495 struct font_mapping
497 struct list entry;
498 int refcount;
499 dev_t dev;
500 ino_t ino;
501 void *data;
502 size_t size;
505 static struct list mappings_list = LIST_INIT( mappings_list );
507 static CRITICAL_SECTION freetype_cs;
508 static CRITICAL_SECTION_DEBUG critsect_debug =
510 0, 0, &freetype_cs,
511 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
512 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
514 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
516 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
518 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
519 static BOOL use_default_fallback = FALSE;
521 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
523 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
524 'W','i','n','d','o','w','s',' ','N','T','\\',
525 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
526 'S','y','s','t','e','m','L','i','n','k',0};
528 /****************************************
529 * Notes on .fon files
531 * The fonts System, FixedSys and Terminal are special. There are typically multiple
532 * versions installed for different resolutions and codepages. Windows stores which one to use
533 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
534 * Key Meaning
535 * FIXEDFON.FON FixedSys
536 * FONTS.FON System
537 * OEMFONT.FON Terminal
538 * LogPixels Current dpi set by the display control panel applet
539 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
540 * also has a LogPixels value that appears to mirror this)
542 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
543 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
544 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
545 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
546 * so that makes sense.
548 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
549 * to be mapped into the registry on Windows 2000 at least).
550 * I have
551 * woafont=app850.fon
552 * ega80woa.fon=ega80850.fon
553 * ega40woa.fon=ega40850.fon
554 * cga80woa.fon=cga80850.fon
555 * cga40woa.fon=cga40850.fon
558 /* These are all structures needed for the GSUB table */
560 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
561 #define TATEGAKI_LOWER_BOUND 0x02F1
563 typedef struct {
564 DWORD version;
565 WORD ScriptList;
566 WORD FeatureList;
567 WORD LookupList;
568 } GSUB_Header;
570 typedef struct {
571 CHAR ScriptTag[4];
572 WORD Script;
573 } GSUB_ScriptRecord;
575 typedef struct {
576 WORD ScriptCount;
577 GSUB_ScriptRecord ScriptRecord[1];
578 } GSUB_ScriptList;
580 typedef struct {
581 CHAR LangSysTag[4];
582 WORD LangSys;
583 } GSUB_LangSysRecord;
585 typedef struct {
586 WORD DefaultLangSys;
587 WORD LangSysCount;
588 GSUB_LangSysRecord LangSysRecord[1];
589 } GSUB_Script;
591 typedef struct {
592 WORD LookupOrder; /* Reserved */
593 WORD ReqFeatureIndex;
594 WORD FeatureCount;
595 WORD FeatureIndex[1];
596 } GSUB_LangSys;
598 typedef struct {
599 CHAR FeatureTag[4];
600 WORD Feature;
601 } GSUB_FeatureRecord;
603 typedef struct {
604 WORD FeatureCount;
605 GSUB_FeatureRecord FeatureRecord[1];
606 } GSUB_FeatureList;
608 typedef struct {
609 WORD FeatureParams; /* Reserved */
610 WORD LookupCount;
611 WORD LookupListIndex[1];
612 } GSUB_Feature;
614 typedef struct {
615 WORD LookupCount;
616 WORD Lookup[1];
617 } GSUB_LookupList;
619 typedef struct {
620 WORD LookupType;
621 WORD LookupFlag;
622 WORD SubTableCount;
623 WORD SubTable[1];
624 } GSUB_LookupTable;
626 typedef struct {
627 WORD CoverageFormat;
628 WORD GlyphCount;
629 WORD GlyphArray[1];
630 } GSUB_CoverageFormat1;
632 typedef struct {
633 WORD Start;
634 WORD End;
635 WORD StartCoverageIndex;
636 } GSUB_RangeRecord;
638 typedef struct {
639 WORD CoverageFormat;
640 WORD RangeCount;
641 GSUB_RangeRecord RangeRecord[1];
642 } GSUB_CoverageFormat2;
644 typedef struct {
645 WORD SubstFormat; /* = 1 */
646 WORD Coverage;
647 WORD DeltaGlyphID;
648 } GSUB_SingleSubstFormat1;
650 typedef struct {
651 WORD SubstFormat; /* = 2 */
652 WORD Coverage;
653 WORD GlyphCount;
654 WORD Substitute[1];
655 }GSUB_SingleSubstFormat2;
657 #ifdef HAVE_CARBON_CARBON_H
658 static char *find_cache_dir(void)
660 FSRef ref;
661 OSErr err;
662 static char cached_path[MAX_PATH];
663 static const char *wine = "/Wine", *fonts = "/Fonts";
665 if(*cached_path) return cached_path;
667 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
668 if(err != noErr)
670 WARN("can't create cached data folder\n");
671 return NULL;
673 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
674 if(err != noErr)
676 WARN("can't create cached data path\n");
677 *cached_path = '\0';
678 return NULL;
680 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
682 ERR("Could not create full path\n");
683 *cached_path = '\0';
684 return NULL;
686 strcat(cached_path, wine);
688 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
690 WARN("Couldn't mkdir %s\n", cached_path);
691 *cached_path = '\0';
692 return NULL;
694 strcat(cached_path, fonts);
695 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
697 WARN("Couldn't mkdir %s\n", cached_path);
698 *cached_path = '\0';
699 return NULL;
701 return cached_path;
704 /******************************************************************
705 * expand_mac_font
707 * Extracts individual TrueType font files from a Mac suitcase font
708 * and saves them into the user's caches directory (see
709 * find_cache_dir()).
710 * Returns a NULL terminated array of filenames.
712 * We do this because they are apps that try to read ttf files
713 * themselves and they don't like Mac suitcase files.
715 static char **expand_mac_font(const char *path)
717 FSRef ref;
718 SInt16 res_ref;
719 OSStatus s;
720 unsigned int idx;
721 const char *out_dir;
722 const char *filename;
723 int output_len;
724 struct {
725 char **array;
726 unsigned int size, max_size;
727 } ret;
729 TRACE("path %s\n", path);
731 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
732 if(s != noErr)
734 WARN("failed to get ref\n");
735 return NULL;
738 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
739 if(s != noErr)
741 TRACE("no data fork, so trying resource fork\n");
742 res_ref = FSOpenResFile(&ref, fsRdPerm);
743 if(res_ref == -1)
745 TRACE("unable to open resource fork\n");
746 return NULL;
750 ret.size = 0;
751 ret.max_size = 10;
752 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
753 if(!ret.array)
755 CloseResFile(res_ref);
756 return NULL;
759 out_dir = find_cache_dir();
761 filename = strrchr(path, '/');
762 if(!filename) filename = path;
763 else filename++;
765 /* output filename has the form out_dir/filename_%04x.ttf */
766 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
768 UseResFile(res_ref);
769 idx = 1;
770 while(1)
772 FamRec *fam_rec;
773 unsigned short *num_faces_ptr, num_faces, face;
774 AsscEntry *assoc;
775 Handle fond;
776 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
778 fond = Get1IndResource(fond_res, idx);
779 if(!fond) break;
780 TRACE("got fond resource %d\n", idx);
781 HLock(fond);
783 fam_rec = *(FamRec**)fond;
784 num_faces_ptr = (unsigned short *)(fam_rec + 1);
785 num_faces = GET_BE_WORD(*num_faces_ptr);
786 num_faces++;
787 assoc = (AsscEntry*)(num_faces_ptr + 1);
788 TRACE("num faces %04x\n", num_faces);
789 for(face = 0; face < num_faces; face++, assoc++)
791 Handle sfnt;
792 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
793 unsigned short size, font_id;
794 char *output;
796 size = GET_BE_WORD(assoc->fontSize);
797 font_id = GET_BE_WORD(assoc->fontID);
798 if(size != 0)
800 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
801 continue;
804 TRACE("trying to load sfnt id %04x\n", font_id);
805 sfnt = GetResource(sfnt_res, font_id);
806 if(!sfnt)
808 TRACE("can't get sfnt resource %04x\n", font_id);
809 continue;
812 output = HeapAlloc(GetProcessHeap(), 0, output_len);
813 if(output)
815 int fd;
817 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
819 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
820 if(fd != -1 || errno == EEXIST)
822 if(fd != -1)
824 unsigned char *sfnt_data;
826 HLock(sfnt);
827 sfnt_data = *(unsigned char**)sfnt;
828 write(fd, sfnt_data, GetHandleSize(sfnt));
829 HUnlock(sfnt);
830 close(fd);
832 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
834 ret.max_size *= 2;
835 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
837 ret.array[ret.size++] = output;
839 else
841 WARN("unable to create %s\n", output);
842 HeapFree(GetProcessHeap(), 0, output);
845 ReleaseResource(sfnt);
847 HUnlock(fond);
848 ReleaseResource(fond);
849 idx++;
851 CloseResFile(res_ref);
853 return ret.array;
856 #endif /* HAVE_CARBON_CARBON_H */
858 static inline BOOL is_win9x(void)
860 return GetVersion() & 0x80000000;
863 This function builds an FT_Fixed from a double. It fails if the absolute
864 value of the float number is greater than 32768.
866 static inline FT_Fixed FT_FixedFromFloat(double f)
868 return f * 0x10000;
872 This function builds an FT_Fixed from a FIXED. It simply put f.value
873 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
875 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
877 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
881 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
883 Family *family;
884 Face *face;
885 const char *file;
886 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
887 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
889 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
890 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
892 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
894 if(face_name && strcmpiW(face_name, family->FamilyName))
895 continue;
896 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
898 if (!face->file)
899 continue;
900 file = strrchr(face->file, '/');
901 if(!file)
902 file = face->file;
903 else
904 file++;
905 if(!strcasecmp(file, file_nameA))
907 HeapFree(GetProcessHeap(), 0, file_nameA);
908 return face;
912 HeapFree(GetProcessHeap(), 0, file_nameA);
913 return NULL;
916 static Family *find_family_from_name(const WCHAR *name)
918 Family *family;
920 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
922 if(!strcmpiW(family->FamilyName, name))
923 return family;
926 return NULL;
929 static void DumpSubstList(void)
931 FontSubst *psub;
933 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
935 if(psub->from.charset != -1 || psub->to.charset != -1)
936 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
937 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
938 else
939 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
940 debugstr_w(psub->to.name));
942 return;
945 static LPWSTR strdupW(LPCWSTR p)
947 LPWSTR ret;
948 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
949 ret = HeapAlloc(GetProcessHeap(), 0, len);
950 memcpy(ret, p, len);
951 return ret;
954 static LPSTR strdupA(LPCSTR p)
956 LPSTR ret;
957 DWORD len = (strlen(p) + 1);
958 ret = HeapAlloc(GetProcessHeap(), 0, len);
959 memcpy(ret, p, len);
960 return ret;
963 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
964 INT from_charset)
966 FontSubst *element;
968 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
970 if(!strcmpiW(element->from.name, from_name) &&
971 (element->from.charset == from_charset ||
972 element->from.charset == -1))
973 return element;
976 return NULL;
979 #define ADD_FONT_SUBST_FORCE 1
981 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
983 FontSubst *from_exist, *to_exist;
985 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
987 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
989 list_remove(&from_exist->entry);
990 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
991 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
992 HeapFree(GetProcessHeap(), 0, from_exist);
993 from_exist = NULL;
996 if(!from_exist)
998 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1000 if(to_exist)
1002 HeapFree(GetProcessHeap(), 0, subst->to.name);
1003 subst->to.name = strdupW(to_exist->to.name);
1006 list_add_tail(subst_list, &subst->entry);
1008 return TRUE;
1011 HeapFree(GetProcessHeap(), 0, subst->from.name);
1012 HeapFree(GetProcessHeap(), 0, subst->to.name);
1013 HeapFree(GetProcessHeap(), 0, subst);
1014 return FALSE;
1017 static void split_subst_info(NameCs *nc, LPSTR str)
1019 CHAR *p = strrchr(str, ',');
1020 DWORD len;
1022 nc->charset = -1;
1023 if(p && *(p+1)) {
1024 nc->charset = strtol(p+1, NULL, 10);
1025 *p = '\0';
1027 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1028 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1029 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1032 static void LoadSubstList(void)
1034 FontSubst *psub;
1035 HKEY hkey;
1036 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1037 LPSTR value;
1038 LPVOID data;
1040 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1041 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1042 &hkey) == ERROR_SUCCESS) {
1044 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1045 &valuelen, &datalen, NULL, NULL);
1047 valuelen++; /* returned value doesn't include room for '\0' */
1048 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1049 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1051 dlen = datalen;
1052 vlen = valuelen;
1053 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1054 &dlen) == ERROR_SUCCESS) {
1055 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1057 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1058 split_subst_info(&psub->from, value);
1059 split_subst_info(&psub->to, data);
1061 /* Win 2000 doesn't allow mapping between different charsets
1062 or mapping of DEFAULT_CHARSET */
1063 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1064 psub->to.charset == DEFAULT_CHARSET) {
1065 HeapFree(GetProcessHeap(), 0, psub->to.name);
1066 HeapFree(GetProcessHeap(), 0, psub->from.name);
1067 HeapFree(GetProcessHeap(), 0, psub);
1068 } else {
1069 add_font_subst(&font_subst_list, psub, 0);
1071 /* reset dlen and vlen */
1072 dlen = datalen;
1073 vlen = valuelen;
1075 HeapFree(GetProcessHeap(), 0, data);
1076 HeapFree(GetProcessHeap(), 0, value);
1077 RegCloseKey(hkey);
1082 /*****************************************************************
1083 * get_name_table_entry
1085 * Supply the platform, encoding, language and name ids in req
1086 * and if the name exists the function will fill in the string
1087 * and string_len members. The string is owned by FreeType so
1088 * don't free it. Returns TRUE if the name is found else FALSE.
1090 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1092 FT_SfntName name;
1093 FT_UInt num_names, name_index;
1095 if(FT_IS_SFNT(ft_face))
1097 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1099 for(name_index = 0; name_index < num_names; name_index++)
1101 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1103 if((name.platform_id == req->platform_id) &&
1104 (name.encoding_id == req->encoding_id) &&
1105 (name.language_id == req->language_id) &&
1106 (name.name_id == req->name_id))
1108 req->string = name.string;
1109 req->string_len = name.string_len;
1110 return TRUE;
1115 req->string = NULL;
1116 req->string_len = 0;
1117 return FALSE;
1120 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1122 WCHAR *ret = NULL;
1123 FT_SfntName name;
1125 name.platform_id = TT_PLATFORM_MICROSOFT;
1126 name.encoding_id = TT_MS_ID_UNICODE_CS;
1127 name.language_id = language_id;
1128 name.name_id = name_id;
1130 if(get_name_table_entry(ft_face, &name))
1132 FT_UInt i;
1134 /* String is not nul terminated and string_len is a byte length. */
1135 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1136 for(i = 0; i < name.string_len / 2; i++)
1138 WORD *tmp = (WORD *)&name.string[i * 2];
1139 ret[i] = GET_BE_WORD(*tmp);
1141 ret[i] = 0;
1142 TRACE("Got localised name %s\n", debugstr_w(ret));
1145 return ret;
1148 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1150 DWORD type, needed;
1151 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1152 if(r != ERROR_SUCCESS) return r;
1153 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1154 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1157 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1159 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1162 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1164 DWORD needed;
1165 DWORD num_strikes, max_strike_key_len;
1167 /* If we have a File Name key then this is a real font, not just the parent
1168 key of a bunch of non-scalable strikes */
1169 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1171 DWORD italic, bold;
1172 Face *face;
1173 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1174 face->cached_enum_data = NULL;
1176 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1177 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1179 face->StyleName = strdupW(face_name);
1180 face->family = family;
1182 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1184 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1185 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1186 face->FullName = fullName;
1188 else
1189 face->FullName = NULL;
1191 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1192 reg_load_dword(hkey_face, face_italic_value, &italic);
1193 reg_load_dword(hkey_face, face_bold_value, &bold);
1194 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1195 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1197 needed = sizeof(face->fs);
1198 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1199 memset(&face->fs_links, 0, sizeof(face->fs_links));
1201 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1203 face->scalable = TRUE;
1204 memset(&face->size, 0, sizeof(face->size));
1206 else
1208 face->scalable = FALSE;
1209 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1210 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1211 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1212 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1213 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1215 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1216 face->size.height, face->size.width, face->size.size >> 6,
1217 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1220 face->ntmFlags = 0;
1221 if (italic) face->ntmFlags |= NTM_ITALIC;
1222 if (bold) face->ntmFlags |= NTM_BOLD;
1223 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1225 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1226 face->fs.fsCsb[0], face->fs.fsCsb[1],
1227 face->fs.fsUsb[0], face->fs.fsUsb[1],
1228 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1230 if(!italic && !bold)
1231 list_add_head(&family->faces, &face->entry);
1232 else
1233 list_add_tail(&family->faces, &face->entry);
1235 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1238 /* do we have any bitmap strikes? */
1239 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1240 NULL, NULL, NULL, NULL);
1241 if(num_strikes != 0)
1243 WCHAR strike_name[10];
1244 DWORD strike_index = 0;
1246 needed = sizeof(strike_name) / sizeof(WCHAR);
1247 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1248 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1250 HKEY hkey_strike;
1251 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1252 load_face(hkey_strike, face_name, family);
1253 RegCloseKey(hkey_strike);
1254 needed = sizeof(strike_name) / sizeof(WCHAR);
1259 static void load_font_list_from_cache(HKEY hkey_font_cache)
1261 DWORD max_family_key_len, size;
1262 WCHAR *family_name;
1263 DWORD family_index = 0;
1264 Family *family;
1265 HKEY hkey_family;
1267 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1268 NULL, NULL, NULL, NULL);
1269 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1271 size = max_family_key_len + 1;
1272 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1273 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1275 WCHAR *english_family = NULL;
1276 DWORD face_index = 0;
1277 WCHAR *face_name;
1278 DWORD max_face_key_len;
1280 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1281 TRACE("opened family key %s\n", debugstr_w(family_name));
1282 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1284 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1285 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1288 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1289 family->FamilyName = strdupW(family_name);
1290 family->EnglishName = english_family;
1291 list_init(&family->faces);
1292 list_add_tail(&font_list, &family->entry);
1294 if(english_family)
1296 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1297 subst->from.name = strdupW(english_family);
1298 subst->from.charset = -1;
1299 subst->to.name = strdupW(family_name);
1300 subst->to.charset = -1;
1301 add_font_subst(&font_subst_list, subst, 0);
1304 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1305 NULL, NULL, NULL, NULL);
1307 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1308 size = max_face_key_len + 1;
1309 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1310 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1312 HKEY hkey_face;
1314 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1315 load_face(hkey_face, face_name, family);
1316 RegCloseKey(hkey_face);
1317 size = max_face_key_len + 1;
1319 HeapFree(GetProcessHeap(), 0, face_name);
1320 RegCloseKey(hkey_family);
1321 size = max_family_key_len + 1;
1324 HeapFree(GetProcessHeap(), 0, family_name);
1327 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1329 LONG ret;
1330 HKEY hkey_wine_fonts;
1332 /* We don't want to create the fonts key as volatile, so open this first */
1333 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1334 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1335 if(ret != ERROR_SUCCESS)
1337 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1338 return ret;
1341 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1342 KEY_ALL_ACCESS, NULL, hkey, disposition);
1343 RegCloseKey(hkey_wine_fonts);
1344 return ret;
1347 static void add_face_to_cache(Face *face)
1349 HKEY hkey_font_cache, hkey_family, hkey_face;
1350 WCHAR *face_key_name;
1352 create_font_cache_key(&hkey_font_cache, NULL);
1354 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1355 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1356 if(face->family->EnglishName)
1357 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1358 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1360 if(face->scalable)
1361 face_key_name = face->StyleName;
1362 else
1364 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1365 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1366 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1368 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1369 &hkey_face, NULL);
1370 if(!face->scalable)
1371 HeapFree(GetProcessHeap(), 0, face_key_name);
1373 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1374 if (face->FullName)
1375 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1376 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1378 reg_save_dword(hkey_face, face_index_value, face->face_index);
1379 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1380 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1381 reg_save_dword(hkey_face, face_version_value, face->font_version);
1382 reg_save_dword(hkey_face, face_external_value, face->external);
1384 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1386 if(!face->scalable)
1388 reg_save_dword(hkey_face, face_height_value, face->size.height);
1389 reg_save_dword(hkey_face, face_width_value, face->size.width);
1390 reg_save_dword(hkey_face, face_size_value, face->size.size);
1391 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1392 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1393 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1395 RegCloseKey(hkey_face);
1396 RegCloseKey(hkey_family);
1397 RegCloseKey(hkey_font_cache);
1400 static inline int TestStyles(DWORD flags, DWORD styles)
1402 return (flags & styles) == styles;
1405 static int StyleOrdering(Face *face)
1407 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1408 return 3;
1409 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1410 return 2;
1411 if (TestStyles(face->ntmFlags, NTM_BOLD))
1412 return 1;
1413 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1414 return 0;
1416 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1417 debugstr_w(face->family->FamilyName),
1418 debugstr_w(face->StyleName),
1419 face->ntmFlags);
1421 return 9999;
1424 /* Add a style of face to a font family using an ordering of the list such
1425 that regular fonts come before bold and italic, and single styles come
1426 before compound styles. */
1427 static void AddFaceToFamily(Face *face, Family *family)
1429 struct list *entry;
1431 LIST_FOR_EACH( entry, &family->faces )
1433 Face *ent = LIST_ENTRY(entry, Face, entry);
1434 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1436 list_add_before( entry, &face->entry );
1439 #define ADDFONT_EXTERNAL_FONT 0x01
1440 #define ADDFONT_FORCE_BITMAP 0x02
1441 #define ADDFONT_ADD_TO_CACHE 0x04
1443 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1445 FT_Face ft_face;
1446 TT_OS2 *pOS2;
1447 TT_Header *pHeader = NULL;
1448 WCHAR *english_family, *localised_family, *StyleW;
1449 DWORD len;
1450 Family *family;
1451 Face *face;
1452 struct list *family_elem_ptr, *face_elem_ptr;
1453 FT_Error err;
1454 FT_Long face_index = 0, num_faces;
1455 #ifdef HAVE_FREETYPE_FTWINFNT_H
1456 FT_WinFNT_HeaderRec winfnt_header;
1457 #endif
1458 int i, bitmap_num, internal_leading;
1459 FONTSIGNATURE fs;
1461 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1462 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1464 #ifdef HAVE_CARBON_CARBON_H
1465 if(file && !fake_family)
1467 char **mac_list = expand_mac_font(file);
1468 if(mac_list)
1470 BOOL had_one = FALSE;
1471 char **cursor;
1472 for(cursor = mac_list; *cursor; cursor++)
1474 had_one = TRUE;
1475 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1476 HeapFree(GetProcessHeap(), 0, *cursor);
1478 HeapFree(GetProcessHeap(), 0, mac_list);
1479 if(had_one)
1480 return 1;
1483 #endif /* HAVE_CARBON_CARBON_H */
1485 do {
1486 char *family_name = fake_family;
1488 if (file)
1490 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1491 err = pFT_New_Face(library, file, face_index, &ft_face);
1492 } else
1494 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1495 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1498 if(err != 0) {
1499 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1500 return 0;
1503 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1504 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1505 pFT_Done_Face(ft_face);
1506 return 0;
1509 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1510 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1511 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1512 pFT_Done_Face(ft_face);
1513 return 0;
1516 if(FT_IS_SFNT(ft_face))
1518 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1519 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1520 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1522 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1523 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1524 pFT_Done_Face(ft_face);
1525 return 0;
1528 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1529 we don't want to load these. */
1530 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1532 FT_ULong len = 0;
1534 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1536 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1537 pFT_Done_Face(ft_face);
1538 return 0;
1543 if(!ft_face->family_name || !ft_face->style_name) {
1544 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1545 pFT_Done_Face(ft_face);
1546 return 0;
1549 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1551 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1552 pFT_Done_Face(ft_face);
1553 return 0;
1556 if (target_family)
1558 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1559 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1561 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1562 HeapFree(GetProcessHeap(), 0, localised_family);
1563 num_faces = ft_face->num_faces;
1564 pFT_Done_Face(ft_face);
1565 continue;
1567 HeapFree(GetProcessHeap(), 0, localised_family);
1570 if(!family_name)
1571 family_name = ft_face->family_name;
1573 bitmap_num = 0;
1574 do {
1575 My_FT_Bitmap_Size *size = NULL;
1576 FT_ULong tmp_size;
1578 if(!FT_IS_SCALABLE(ft_face))
1579 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1581 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1582 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1583 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1585 localised_family = NULL;
1586 if(!fake_family) {
1587 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1588 if(localised_family && !strcmpiW(localised_family, english_family)) {
1589 HeapFree(GetProcessHeap(), 0, localised_family);
1590 localised_family = NULL;
1594 family = NULL;
1595 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1596 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1597 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1598 break;
1599 family = NULL;
1601 if(!family) {
1602 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1603 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1604 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1605 list_init(&family->faces);
1606 list_add_tail(&font_list, &family->entry);
1608 if(localised_family) {
1609 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1610 subst->from.name = strdupW(english_family);
1611 subst->from.charset = -1;
1612 subst->to.name = strdupW(localised_family);
1613 subst->to.charset = -1;
1614 add_font_subst(&font_subst_list, subst, 0);
1617 HeapFree(GetProcessHeap(), 0, localised_family);
1618 HeapFree(GetProcessHeap(), 0, english_family);
1620 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1621 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1622 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1624 internal_leading = 0;
1625 memset(&fs, 0, sizeof(fs));
1627 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1628 if(pOS2) {
1629 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1630 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1631 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1632 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1633 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1634 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1635 if(pOS2->version == 0) {
1636 FT_UInt dummy;
1638 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1639 fs.fsCsb[0] |= FS_LATIN1;
1640 else
1641 fs.fsCsb[0] |= FS_SYMBOL;
1644 #ifdef HAVE_FREETYPE_FTWINFNT_H
1645 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1646 CHARSETINFO csi;
1647 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1648 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1649 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1650 fs = csi.fs;
1651 internal_leading = winfnt_header.internal_leading;
1653 #endif
1655 face_elem_ptr = list_head(&family->faces);
1656 while(face_elem_ptr) {
1657 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1658 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1659 if(!strcmpiW(face->StyleName, StyleW) &&
1660 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1661 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1662 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1663 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1665 if(fake_family) {
1666 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1667 HeapFree(GetProcessHeap(), 0, StyleW);
1668 pFT_Done_Face(ft_face);
1669 return 1;
1671 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1672 TRACE("Original font is newer so skipping this one\n");
1673 HeapFree(GetProcessHeap(), 0, StyleW);
1674 pFT_Done_Face(ft_face);
1675 return 1;
1676 } else {
1677 TRACE("Replacing original with this one\n");
1678 list_remove(&face->entry);
1679 HeapFree(GetProcessHeap(), 0, face->file);
1680 HeapFree(GetProcessHeap(), 0, face->StyleName);
1681 HeapFree(GetProcessHeap(), 0, face->FullName);
1682 HeapFree(GetProcessHeap(), 0, face);
1683 break;
1687 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1688 face->cached_enum_data = NULL;
1689 face->StyleName = StyleW;
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;
1703 face->face_index = face_index;
1704 face->ntmFlags = 0;
1705 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1706 face->ntmFlags |= NTM_ITALIC;
1707 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1708 face->ntmFlags |= NTM_BOLD;
1709 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1710 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1711 face->family = family;
1712 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1713 face->fs = fs;
1714 memset(&face->fs_links, 0, sizeof(face->fs_links));
1716 if(FT_IS_SCALABLE(ft_face)) {
1717 memset(&face->size, 0, sizeof(face->size));
1718 face->scalable = TRUE;
1719 } else {
1720 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1721 size->height, size->width, size->size >> 6,
1722 size->x_ppem >> 6, size->y_ppem >> 6);
1723 face->size.height = size->height;
1724 face->size.width = size->width;
1725 face->size.size = size->size;
1726 face->size.x_ppem = size->x_ppem;
1727 face->size.y_ppem = size->y_ppem;
1728 face->size.internal_leading = internal_leading;
1729 face->scalable = FALSE;
1732 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1733 tmp_size = 0;
1734 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1736 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1737 face->ntmFlags |= NTM_PS_OPENTYPE;
1740 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1741 face->fs.fsCsb[0], face->fs.fsCsb[1],
1742 face->fs.fsUsb[0], face->fs.fsUsb[1],
1743 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1746 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1747 for(i = 0; i < ft_face->num_charmaps; i++) {
1748 switch(ft_face->charmaps[i]->encoding) {
1749 case FT_ENCODING_UNICODE:
1750 case FT_ENCODING_APPLE_ROMAN:
1751 face->fs.fsCsb[0] |= FS_LATIN1;
1752 break;
1753 case FT_ENCODING_MS_SYMBOL:
1754 face->fs.fsCsb[0] |= FS_SYMBOL;
1755 break;
1756 default:
1757 break;
1762 if(flags & ADDFONT_ADD_TO_CACHE)
1763 add_face_to_cache(face);
1765 AddFaceToFamily(face, family);
1767 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1769 num_faces = ft_face->num_faces;
1770 pFT_Done_Face(ft_face);
1771 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1772 debugstr_w(StyleW));
1773 } while(num_faces > ++face_index);
1774 return num_faces;
1777 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1779 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1782 static void DumpFontList(void)
1784 Family *family;
1785 Face *face;
1786 struct list *family_elem_ptr, *face_elem_ptr;
1788 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1789 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1790 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1791 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1792 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1793 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1794 if(!face->scalable)
1795 TRACE(" %d", face->size.height);
1796 TRACE("\n");
1799 return;
1802 /***********************************************************
1803 * The replacement list is a way to map an entire font
1804 * family onto another family. For example adding
1806 * [HKCU\Software\Wine\Fonts\Replacements]
1807 * "Wingdings"="Winedings"
1809 * would enumerate the Winedings font both as Winedings and
1810 * Wingdings. However if a real Wingdings font is present the
1811 * replacement does not take place.
1814 static void LoadReplaceList(void)
1816 HKEY hkey;
1817 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1818 LPWSTR value;
1819 LPVOID data;
1820 Family *family;
1821 Face *face;
1822 struct list *family_elem_ptr, *face_elem_ptr;
1823 CHAR familyA[400];
1825 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1826 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1828 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1829 &valuelen, &datalen, NULL, NULL);
1831 valuelen++; /* returned value doesn't include room for '\0' */
1832 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1833 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1835 dlen = datalen;
1836 vlen = valuelen;
1837 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1838 &dlen) == ERROR_SUCCESS) {
1839 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1840 /* "NewName"="Oldname" */
1841 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1843 if(!find_family_from_name(value))
1845 /* Find the old family and hence all of the font files
1846 in that family */
1847 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1848 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1849 if(!strcmpiW(family->FamilyName, data)) {
1850 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1851 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1852 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1853 debugstr_w(face->StyleName), familyA);
1854 /* Now add a new entry with the new family name */
1855 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1856 familyA, family->FamilyName,
1857 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1859 break;
1863 /* reset dlen and vlen */
1864 dlen = datalen;
1865 vlen = valuelen;
1867 HeapFree(GetProcessHeap(), 0, data);
1868 HeapFree(GetProcessHeap(), 0, value);
1869 RegCloseKey(hkey);
1873 /*************************************************************
1874 * init_system_links
1876 static BOOL init_system_links(void)
1878 HKEY hkey;
1879 BOOL ret = FALSE;
1880 DWORD type, max_val, max_data, val_len, data_len, index;
1881 WCHAR *value, *data;
1882 WCHAR *entry, *next;
1883 SYSTEM_LINKS *font_link, *system_font_link;
1884 CHILD_FONT *child_font;
1885 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1886 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1887 FONTSIGNATURE fs;
1888 Family *family;
1889 Face *face;
1890 FontSubst *psub;
1892 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1894 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1895 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1896 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1897 val_len = max_val + 1;
1898 data_len = max_data;
1899 index = 0;
1900 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1902 memset(&fs, 0, sizeof(fs));
1903 psub = get_font_subst(&font_subst_list, value, -1);
1904 /* Don't store fonts that are only substitutes for other fonts */
1905 if(psub)
1907 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1908 goto next;
1910 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1911 font_link->font_name = strdupW(value);
1912 list_init(&font_link->links);
1913 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1915 WCHAR *face_name;
1916 CHILD_FONT *child_font;
1918 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1920 next = entry + strlenW(entry) + 1;
1922 face_name = strchrW(entry, ',');
1923 if(face_name)
1925 *face_name++ = 0;
1926 while(isspaceW(*face_name))
1927 face_name++;
1929 psub = get_font_subst(&font_subst_list, face_name, -1);
1930 if(psub)
1931 face_name = psub->to.name;
1933 face = find_face_from_filename(entry, face_name);
1934 if(!face)
1936 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1937 continue;
1940 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1941 child_font->face = face;
1942 child_font->font = NULL;
1943 fs.fsCsb[0] |= face->fs.fsCsb[0];
1944 fs.fsCsb[1] |= face->fs.fsCsb[1];
1945 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1946 list_add_tail(&font_link->links, &child_font->entry);
1948 family = find_family_from_name(font_link->font_name);
1949 if(family)
1951 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1953 face->fs_links = fs;
1956 list_add_tail(&system_links, &font_link->entry);
1957 next:
1958 val_len = max_val + 1;
1959 data_len = max_data;
1962 HeapFree(GetProcessHeap(), 0, value);
1963 HeapFree(GetProcessHeap(), 0, data);
1964 RegCloseKey(hkey);
1967 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1968 that Tahoma has */
1970 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1971 system_font_link->font_name = strdupW(System);
1972 list_init(&system_font_link->links);
1974 face = find_face_from_filename(tahoma_ttf, Tahoma);
1975 if(face)
1977 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1978 child_font->face = face;
1979 child_font->font = NULL;
1980 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1981 list_add_tail(&system_font_link->links, &child_font->entry);
1983 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1985 if(!strcmpiW(font_link->font_name, Tahoma))
1987 CHILD_FONT *font_link_entry;
1988 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1990 CHILD_FONT *new_child;
1991 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1992 new_child->face = font_link_entry->face;
1993 new_child->font = NULL;
1994 list_add_tail(&system_font_link->links, &new_child->entry);
1996 break;
1999 list_add_tail(&system_links, &system_font_link->entry);
2000 return ret;
2003 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2005 DIR *dir;
2006 struct dirent *dent;
2007 char path[MAX_PATH];
2009 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2011 dir = opendir(dirname);
2012 if(!dir) {
2013 WARN("Can't open directory %s\n", debugstr_a(dirname));
2014 return FALSE;
2016 while((dent = readdir(dir)) != NULL) {
2017 struct stat statbuf;
2019 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2020 continue;
2022 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2024 sprintf(path, "%s/%s", dirname, dent->d_name);
2026 if(stat(path, &statbuf) == -1)
2028 WARN("Can't stat %s\n", debugstr_a(path));
2029 continue;
2031 if(S_ISDIR(statbuf.st_mode))
2032 ReadFontDir(path, external_fonts);
2033 else
2035 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2036 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2037 AddFontFileToList(path, NULL, NULL, addfont_flags);
2040 closedir(dir);
2041 return TRUE;
2044 static void load_fontconfig_fonts(void)
2046 #ifdef SONAME_LIBFONTCONFIG
2047 void *fc_handle = NULL;
2048 FcConfig *config;
2049 FcPattern *pat;
2050 FcObjectSet *os;
2051 FcFontSet *fontset;
2052 int i, len;
2053 char *file;
2054 const char *ext;
2056 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2057 if(!fc_handle) {
2058 TRACE("Wine cannot find the fontconfig library (%s).\n",
2059 SONAME_LIBFONTCONFIG);
2060 return;
2062 #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;}
2063 LOAD_FUNCPTR(FcConfigGetCurrent);
2064 LOAD_FUNCPTR(FcFontList);
2065 LOAD_FUNCPTR(FcFontSetDestroy);
2066 LOAD_FUNCPTR(FcInit);
2067 LOAD_FUNCPTR(FcObjectSetAdd);
2068 LOAD_FUNCPTR(FcObjectSetCreate);
2069 LOAD_FUNCPTR(FcObjectSetDestroy);
2070 LOAD_FUNCPTR(FcPatternCreate);
2071 LOAD_FUNCPTR(FcPatternDestroy);
2072 LOAD_FUNCPTR(FcPatternGetBool);
2073 LOAD_FUNCPTR(FcPatternGetString);
2074 #undef LOAD_FUNCPTR
2076 if(!pFcInit()) return;
2078 config = pFcConfigGetCurrent();
2079 pat = pFcPatternCreate();
2080 os = pFcObjectSetCreate();
2081 pFcObjectSetAdd(os, FC_FILE);
2082 pFcObjectSetAdd(os, FC_SCALABLE);
2083 fontset = pFcFontList(config, pat, os);
2084 if(!fontset) return;
2085 for(i = 0; i < fontset->nfont; i++) {
2086 FcBool scalable;
2088 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2089 continue;
2090 TRACE("fontconfig: %s\n", file);
2092 /* We're just interested in OT/TT fonts for now, so this hack just
2093 picks up the scalable fonts without extensions .pf[ab] to save time
2094 loading every other font */
2096 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2098 TRACE("not scalable\n");
2099 continue;
2102 len = strlen( file );
2103 if(len < 4) continue;
2104 ext = &file[ len - 3 ];
2105 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2106 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2108 pFcFontSetDestroy(fontset);
2109 pFcObjectSetDestroy(os);
2110 pFcPatternDestroy(pat);
2111 sym_not_found:
2112 #endif
2113 return;
2116 static BOOL load_font_from_data_dir(LPCWSTR file)
2118 BOOL ret = FALSE;
2119 const char *data_dir = wine_get_data_dir();
2121 if (!data_dir) data_dir = wine_get_build_dir();
2123 if (data_dir)
2125 INT len;
2126 char *unix_name;
2128 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2130 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2132 strcpy(unix_name, data_dir);
2133 strcat(unix_name, "/fonts/");
2135 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2137 EnterCriticalSection( &freetype_cs );
2138 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2139 LeaveCriticalSection( &freetype_cs );
2140 HeapFree(GetProcessHeap(), 0, unix_name);
2142 return ret;
2145 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2147 static const WCHAR slashW[] = {'\\','\0'};
2148 BOOL ret = FALSE;
2149 WCHAR windowsdir[MAX_PATH];
2150 char *unixname;
2152 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2153 strcatW(windowsdir, fontsW);
2154 strcatW(windowsdir, slashW);
2155 strcatW(windowsdir, file);
2156 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2157 EnterCriticalSection( &freetype_cs );
2158 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2159 LeaveCriticalSection( &freetype_cs );
2160 HeapFree(GetProcessHeap(), 0, unixname);
2162 return ret;
2165 static void load_system_fonts(void)
2167 HKEY hkey;
2168 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2169 const WCHAR * const *value;
2170 DWORD dlen, type;
2171 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2172 char *unixname;
2174 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2175 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2176 strcatW(windowsdir, fontsW);
2177 for(value = SystemFontValues; *value; value++) {
2178 dlen = sizeof(data);
2179 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2180 type == REG_SZ) {
2181 BOOL added = FALSE;
2183 sprintfW(pathW, fmtW, windowsdir, data);
2184 if((unixname = wine_get_unix_file_name(pathW))) {
2185 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2186 HeapFree(GetProcessHeap(), 0, unixname);
2188 if (!added)
2189 load_font_from_data_dir(data);
2192 RegCloseKey(hkey);
2196 /*************************************************************
2198 * This adds registry entries for any externally loaded fonts
2199 * (fonts from fontconfig or FontDirs). It also deletes entries
2200 * of no longer existing fonts.
2203 static void update_reg_entries(void)
2205 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2206 LPWSTR valueW;
2207 DWORD len, len_fam;
2208 Family *family;
2209 Face *face;
2210 struct list *family_elem_ptr, *face_elem_ptr;
2211 WCHAR *file;
2212 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2213 static const WCHAR spaceW[] = {' ', '\0'};
2214 char *path;
2216 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2217 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2218 ERR("Can't create Windows font reg key\n");
2219 goto end;
2222 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2223 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2224 ERR("Can't create Windows font reg key\n");
2225 goto end;
2228 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2229 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2230 ERR("Can't create external font reg key\n");
2231 goto end;
2234 /* enumerate the fonts and add external ones to the two keys */
2236 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2237 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2238 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2239 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2240 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2241 if(!face->external) continue;
2242 len = len_fam;
2243 if (!(face->ntmFlags & NTM_REGULAR))
2244 len = len_fam + strlenW(face->StyleName) + 1;
2245 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2246 strcpyW(valueW, family->FamilyName);
2247 if(len != len_fam) {
2248 strcatW(valueW, spaceW);
2249 strcatW(valueW, face->StyleName);
2251 strcatW(valueW, TrueType);
2253 file = wine_get_dos_file_name(face->file);
2254 if(file)
2255 len = strlenW(file) + 1;
2256 else
2258 if((path = strrchr(face->file, '/')) == NULL)
2259 path = face->file;
2260 else
2261 path++;
2262 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2264 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2265 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2267 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2268 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2269 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2271 HeapFree(GetProcessHeap(), 0, file);
2272 HeapFree(GetProcessHeap(), 0, valueW);
2275 end:
2276 if(external_key) RegCloseKey(external_key);
2277 if(win9x_key) RegCloseKey(win9x_key);
2278 if(winnt_key) RegCloseKey(winnt_key);
2279 return;
2282 static void delete_external_font_keys(void)
2284 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2285 DWORD dlen, vlen, datalen, valuelen, i, type;
2286 LPWSTR valueW;
2287 LPVOID data;
2289 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2290 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2291 ERR("Can't create Windows font reg key\n");
2292 goto end;
2295 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2296 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2297 ERR("Can't create Windows font reg key\n");
2298 goto end;
2301 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2302 ERR("Can't create external font reg key\n");
2303 goto end;
2306 /* Delete all external fonts added last time */
2308 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2309 &valuelen, &datalen, NULL, NULL);
2310 valuelen++; /* returned value doesn't include room for '\0' */
2311 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2312 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2314 dlen = datalen * sizeof(WCHAR);
2315 vlen = valuelen;
2316 i = 0;
2317 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2318 &dlen) == ERROR_SUCCESS) {
2320 RegDeleteValueW(winnt_key, valueW);
2321 RegDeleteValueW(win9x_key, valueW);
2322 /* reset dlen and vlen */
2323 dlen = datalen;
2324 vlen = valuelen;
2326 HeapFree(GetProcessHeap(), 0, data);
2327 HeapFree(GetProcessHeap(), 0, valueW);
2329 /* Delete the old external fonts key */
2330 RegCloseKey(external_key);
2331 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2333 end:
2334 if(win9x_key) RegCloseKey(win9x_key);
2335 if(winnt_key) RegCloseKey(winnt_key);
2338 /*************************************************************
2339 * WineEngAddFontResourceEx
2342 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2344 INT ret = 0;
2346 GDI_CheckNotLock();
2348 if (ft_handle) /* do it only if we have freetype up and running */
2350 char *unixname;
2352 if(flags)
2353 FIXME("Ignoring flags %x\n", flags);
2355 if((unixname = wine_get_unix_file_name(file)))
2357 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2359 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2360 EnterCriticalSection( &freetype_cs );
2361 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2362 LeaveCriticalSection( &freetype_cs );
2363 HeapFree(GetProcessHeap(), 0, unixname);
2365 if (!ret && !strchrW(file, '\\')) {
2366 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2367 ret = load_font_from_winfonts_dir(file);
2368 if (!ret) {
2369 /* Try in datadir/fonts (or builddir/fonts),
2370 * needed for Magic the Gathering Online
2372 ret = load_font_from_data_dir(file);
2376 return ret;
2379 /*************************************************************
2380 * WineEngAddFontMemResourceEx
2383 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2385 GDI_CheckNotLock();
2387 if (ft_handle) /* do it only if we have freetype up and running */
2389 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2391 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2392 memcpy(pFontCopy, pbFont, cbFont);
2394 EnterCriticalSection( &freetype_cs );
2395 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2396 LeaveCriticalSection( &freetype_cs );
2398 if (*pcFonts == 0)
2400 TRACE("AddFontToList failed\n");
2401 HeapFree(GetProcessHeap(), 0, pFontCopy);
2402 return 0;
2404 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2405 * For now return something unique but quite random
2407 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2408 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2411 *pcFonts = 0;
2412 return 0;
2415 /*************************************************************
2416 * WineEngRemoveFontResourceEx
2419 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2421 GDI_CheckNotLock();
2422 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2423 return TRUE;
2426 static const struct nls_update_font_list
2428 UINT ansi_cp, oem_cp;
2429 const char *oem, *fixed, *system;
2430 const char *courier, *serif, *small, *sserif;
2431 /* these are for font substitutes */
2432 const char *shelldlg, *tmsrmn;
2433 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2434 *helv_0, *tmsrmn_0;
2435 const struct subst
2437 const char *from, *to;
2438 } arial_0, courier_new_0, times_new_roman_0;
2439 } nls_update_font_list[] =
2441 /* Latin 1 (United States) */
2442 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2443 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2444 "Tahoma","Times New Roman",
2445 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2446 { 0 }, { 0 }, { 0 }
2448 /* Latin 1 (Multilingual) */
2449 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2450 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2451 "Tahoma","Times New Roman", /* FIXME unverified */
2452 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2453 { 0 }, { 0 }, { 0 }
2455 /* Eastern Europe */
2456 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2457 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2458 "Tahoma","Times New Roman", /* FIXME unverified */
2459 "Fixedsys,238", "System,238",
2460 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2461 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2462 { "Arial CE,0", "Arial,238" },
2463 { "Courier New CE,0", "Courier New,238" },
2464 { "Times New Roman CE,0", "Times New Roman,238" }
2466 /* Cyrillic */
2467 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2468 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2469 "Tahoma","Times New Roman", /* FIXME unverified */
2470 "Fixedsys,204", "System,204",
2471 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2472 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2473 { "Arial Cyr,0", "Arial,204" },
2474 { "Courier New Cyr,0", "Courier New,204" },
2475 { "Times New Roman Cyr,0", "Times New Roman,204" }
2477 /* Greek */
2478 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2479 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2480 "Tahoma","Times New Roman", /* FIXME unverified */
2481 "Fixedsys,161", "System,161",
2482 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2483 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2484 { "Arial Greek,0", "Arial,161" },
2485 { "Courier New Greek,0", "Courier New,161" },
2486 { "Times New Roman Greek,0", "Times New Roman,161" }
2488 /* Turkish */
2489 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2490 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2491 "Tahoma","Times New Roman", /* FIXME unverified */
2492 "Fixedsys,162", "System,162",
2493 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2494 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2495 { "Arial Tur,0", "Arial,162" },
2496 { "Courier New Tur,0", "Courier New,162" },
2497 { "Times New Roman Tur,0", "Times New Roman,162" }
2499 /* Hebrew */
2500 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2501 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2502 "Tahoma","Times New Roman", /* FIXME unverified */
2503 "Fixedsys,177", "System,177",
2504 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2505 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2506 { 0 }, { 0 }, { 0 }
2508 /* Arabic */
2509 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2510 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2511 "Tahoma","Times New Roman", /* FIXME unverified */
2512 "Fixedsys,178", "System,178",
2513 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2514 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2515 { 0 }, { 0 }, { 0 }
2517 /* Baltic */
2518 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2519 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2520 "Tahoma","Times New Roman", /* FIXME unverified */
2521 "Fixedsys,186", "System,186",
2522 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2523 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2524 { "Arial Baltic,0", "Arial,186" },
2525 { "Courier New Baltic,0", "Courier New,186" },
2526 { "Times New Roman Baltic,0", "Times New Roman,186" }
2528 /* Vietnamese */
2529 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2530 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2531 "Tahoma","Times New Roman", /* FIXME unverified */
2532 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2533 { 0 }, { 0 }, { 0 }
2535 /* Thai */
2536 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2537 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2538 "Tahoma","Times New Roman", /* FIXME unverified */
2539 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2540 { 0 }, { 0 }, { 0 }
2542 /* Japanese */
2543 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2544 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2545 "MS UI Gothic","MS Serif",
2546 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2547 { 0 }, { 0 }, { 0 }
2549 /* Chinese Simplified */
2550 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2551 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2552 "SimSun", "NSimSun",
2553 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2554 { 0 }, { 0 }, { 0 }
2556 /* Korean */
2557 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2558 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2559 "Gulim", "Batang",
2560 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2561 { 0 }, { 0 }, { 0 }
2563 /* Chinese Traditional */
2564 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2565 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2566 "PMingLiU", "MingLiU",
2567 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2568 { 0 }, { 0 }, { 0 }
2572 static const WCHAR *font_links_list[] =
2574 Lucida_Sans_Unicode,
2575 Microsoft_Sans_Serif,
2576 Tahoma
2579 static const struct font_links_defaults_list
2581 /* Keyed off substitution for "MS Shell Dlg" */
2582 const WCHAR *shelldlg;
2583 /* Maximum of four substitutes, plus terminating NULL pointer */
2584 const WCHAR *substitutes[5];
2585 } font_links_defaults_list[] =
2587 /* Non East-Asian */
2588 { Tahoma, /* FIXME unverified ordering */
2589 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2591 /* Below lists are courtesy of
2592 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2594 /* Japanese */
2595 { MS_UI_Gothic,
2596 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2598 /* Chinese Simplified */
2599 { SimSun,
2600 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2602 /* Korean */
2603 { Gulim,
2604 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2606 /* Chinese Traditional */
2607 { PMingLiU,
2608 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2612 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2614 return ( ansi_cp == 932 /* CP932 for Japanese */
2615 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2616 || ansi_cp == 949 /* CP949 for Korean */
2617 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2620 static inline HKEY create_fonts_NT_registry_key(void)
2622 HKEY hkey = 0;
2624 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2625 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2626 return hkey;
2629 static inline HKEY create_fonts_9x_registry_key(void)
2631 HKEY hkey = 0;
2633 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2634 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2635 return hkey;
2638 static inline HKEY create_config_fonts_registry_key(void)
2640 HKEY hkey = 0;
2642 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2643 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2644 return hkey;
2647 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2649 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2650 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2651 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2652 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2655 static void set_value_key(HKEY hkey, const char *name, const char *value)
2657 if (value)
2658 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2659 else if (name)
2660 RegDeleteValueA(hkey, name);
2663 static void update_font_info(void)
2665 char buf[40], cpbuf[40];
2666 DWORD len, type;
2667 HKEY hkey = 0;
2668 UINT i, ansi_cp = 0, oem_cp = 0;
2669 BOOL done = FALSE;
2671 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2672 return;
2674 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2675 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2676 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2677 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2678 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2680 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2681 if (is_dbcs_ansi_cp(ansi_cp))
2682 use_default_fallback = TRUE;
2684 len = sizeof(buf);
2685 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2687 if (!strcmp( buf, cpbuf )) /* already set correctly */
2689 RegCloseKey(hkey);
2690 return;
2692 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2694 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2696 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2697 RegCloseKey(hkey);
2699 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2701 HKEY hkey;
2703 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2704 nls_update_font_list[i].oem_cp == oem_cp)
2706 hkey = create_config_fonts_registry_key();
2707 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2708 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2709 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2710 RegCloseKey(hkey);
2712 hkey = create_fonts_NT_registry_key();
2713 add_font_list(hkey, &nls_update_font_list[i]);
2714 RegCloseKey(hkey);
2716 hkey = create_fonts_9x_registry_key();
2717 add_font_list(hkey, &nls_update_font_list[i]);
2718 RegCloseKey(hkey);
2720 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2722 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2723 strlen(nls_update_font_list[i].shelldlg)+1);
2724 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2725 strlen(nls_update_font_list[i].tmsrmn)+1);
2727 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2728 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2729 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2730 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2731 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2732 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2733 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2734 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2736 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2737 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2738 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2740 RegCloseKey(hkey);
2742 done = TRUE;
2744 else
2746 /* Delete the FontSubstitutes from other locales */
2747 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2749 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2750 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2751 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2752 RegCloseKey(hkey);
2756 if (!done)
2757 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2759 /* Clear out system links */
2760 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2763 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2765 const WCHAR *value;
2766 int i;
2767 FontSubst *psub;
2768 Family *family;
2769 Face *face;
2770 const char *file;
2771 WCHAR *fileW;
2772 int fileLen;
2773 WCHAR buff[MAX_PATH];
2774 WCHAR *data;
2775 int entryLen;
2777 static const WCHAR comma[] = {',',0};
2779 RegDeleteValueW(hkey, name);
2780 if (values)
2782 data = buff;
2783 data[0] = '\0';
2784 for (i = 0; values[i] != NULL; i++)
2786 value = values[i];
2787 if (!strcmpiW(name,value))
2788 continue;
2789 psub = get_font_subst(&font_subst_list, value, -1);
2790 if(psub)
2791 value = psub->to.name;
2792 family = find_family_from_name(value);
2793 if (!family)
2794 continue;
2795 file = NULL;
2796 /* Use first extant filename for this Family */
2797 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2799 if (!face->file)
2800 continue;
2801 file = strrchr(face->file, '/');
2802 if (!file)
2803 file = face->file;
2804 else
2805 file++;
2806 break;
2808 if (!file)
2809 continue;
2810 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2811 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2812 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2813 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2814 if (sizeof(buff)-(data-buff) < entryLen + 1)
2816 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2817 HeapFree(GetProcessHeap(), 0, fileW);
2818 break;
2820 strcpyW(data, fileW);
2821 strcatW(data, comma);
2822 strcatW(data, value);
2823 data += entryLen;
2824 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2825 HeapFree(GetProcessHeap(), 0, fileW);
2827 if (data != buff)
2829 *data='\0';
2830 data++;
2831 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2832 } else
2833 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2834 } else
2835 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2838 static void update_system_links(void)
2840 HKEY hkey = 0;
2841 UINT i, j;
2842 BOOL done = FALSE;
2843 DWORD disposition;
2844 FontSubst *psub;
2846 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2848 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2850 if (disposition == REG_OPENED_EXISTING_KEY)
2852 TRACE("SystemLink key already exists, doing nothing\n");
2853 RegCloseKey(hkey);
2854 return;
2857 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2858 if (!psub) {
2859 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2860 RegCloseKey(hkey);
2861 return;
2864 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2866 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2868 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2869 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2871 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2872 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2873 done = TRUE;
2875 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2877 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2880 RegCloseKey(hkey);
2881 if (!done)
2882 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2883 } else
2884 WARN("failed to create SystemLink key\n");
2888 static BOOL init_freetype(void)
2890 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2891 if(!ft_handle) {
2892 WINE_MESSAGE(
2893 "Wine cannot find the FreeType font library. To enable Wine to\n"
2894 "use TrueType fonts please install a version of FreeType greater than\n"
2895 "or equal to 2.0.5.\n"
2896 "http://www.freetype.org\n");
2897 return FALSE;
2900 #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;}
2902 LOAD_FUNCPTR(FT_Done_Face)
2903 LOAD_FUNCPTR(FT_Get_Char_Index)
2904 LOAD_FUNCPTR(FT_Get_Module)
2905 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2906 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2907 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2908 LOAD_FUNCPTR(FT_Init_FreeType)
2909 LOAD_FUNCPTR(FT_Load_Glyph)
2910 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2911 LOAD_FUNCPTR(FT_Matrix_Multiply)
2912 #ifndef FT_MULFIX_INLINED
2913 LOAD_FUNCPTR(FT_MulFix)
2914 #endif
2915 LOAD_FUNCPTR(FT_New_Face)
2916 LOAD_FUNCPTR(FT_New_Memory_Face)
2917 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2918 LOAD_FUNCPTR(FT_Outline_Transform)
2919 LOAD_FUNCPTR(FT_Outline_Translate)
2920 LOAD_FUNCPTR(FT_Render_Glyph)
2921 LOAD_FUNCPTR(FT_Select_Charmap)
2922 LOAD_FUNCPTR(FT_Set_Charmap)
2923 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2924 LOAD_FUNCPTR(FT_Vector_Transform)
2925 LOAD_FUNCPTR(FT_Vector_Unit)
2926 #undef LOAD_FUNCPTR
2927 /* Don't warn if these ones are missing */
2928 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2929 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2930 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2931 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2932 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2933 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2934 #endif
2935 #ifdef HAVE_FREETYPE_FTWINFNT_H
2936 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2937 #endif
2939 if(pFT_Init_FreeType(&library) != 0) {
2940 ERR("Can't init FreeType library\n");
2941 wine_dlclose(ft_handle, NULL, 0);
2942 ft_handle = NULL;
2943 return FALSE;
2945 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2946 if (pFT_Library_Version)
2947 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2949 if (FT_Version.major<=0)
2951 FT_Version.major=2;
2952 FT_Version.minor=0;
2953 FT_Version.patch=5;
2955 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2956 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2957 ((FT_Version.minor << 8) & 0x00ff00) |
2958 ((FT_Version.patch ) & 0x0000ff);
2960 return TRUE;
2962 sym_not_found:
2963 WINE_MESSAGE(
2964 "Wine cannot find certain functions that it needs inside the FreeType\n"
2965 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2966 "FreeType to at least version 2.1.4.\n"
2967 "http://www.freetype.org\n");
2968 wine_dlclose(ft_handle, NULL, 0);
2969 ft_handle = NULL;
2970 return FALSE;
2973 static void init_font_list(void)
2975 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2976 static const WCHAR pathW[] = {'P','a','t','h',0};
2977 HKEY hkey;
2978 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2979 WCHAR windowsdir[MAX_PATH];
2980 char *unixname;
2981 const char *data_dir;
2983 delete_external_font_keys();
2985 /* load the system bitmap fonts */
2986 load_system_fonts();
2988 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2989 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2990 strcatW(windowsdir, fontsW);
2991 if((unixname = wine_get_unix_file_name(windowsdir)))
2993 ReadFontDir(unixname, FALSE);
2994 HeapFree(GetProcessHeap(), 0, unixname);
2997 /* load the system truetype fonts */
2998 data_dir = wine_get_data_dir();
2999 if (!data_dir) data_dir = wine_get_build_dir();
3000 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3002 strcpy(unixname, data_dir);
3003 strcat(unixname, "/fonts/");
3004 ReadFontDir(unixname, TRUE);
3005 HeapFree(GetProcessHeap(), 0, unixname);
3008 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3009 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3010 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3011 will skip these. */
3012 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3013 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3014 &hkey) == ERROR_SUCCESS)
3016 LPWSTR data, valueW;
3017 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3018 &valuelen, &datalen, NULL, NULL);
3020 valuelen++; /* returned value doesn't include room for '\0' */
3021 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3022 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3023 if (valueW && data)
3025 dlen = datalen * sizeof(WCHAR);
3026 vlen = valuelen;
3027 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3028 &dlen) == ERROR_SUCCESS)
3030 if(data[0] && (data[1] == ':'))
3032 if((unixname = wine_get_unix_file_name(data)))
3034 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3035 HeapFree(GetProcessHeap(), 0, unixname);
3038 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3040 WCHAR pathW[MAX_PATH];
3041 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3042 BOOL added = FALSE;
3044 sprintfW(pathW, fmtW, windowsdir, data);
3045 if((unixname = wine_get_unix_file_name(pathW)))
3047 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3048 HeapFree(GetProcessHeap(), 0, unixname);
3050 if (!added)
3051 load_font_from_data_dir(data);
3053 /* reset dlen and vlen */
3054 dlen = datalen;
3055 vlen = valuelen;
3058 HeapFree(GetProcessHeap(), 0, data);
3059 HeapFree(GetProcessHeap(), 0, valueW);
3060 RegCloseKey(hkey);
3063 load_fontconfig_fonts();
3065 /* then look in any directories that we've specified in the config file */
3066 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3067 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3069 DWORD len;
3070 LPWSTR valueW;
3071 LPSTR valueA, ptr;
3073 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3075 len += sizeof(WCHAR);
3076 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3077 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3079 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3080 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3081 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3082 TRACE( "got font path %s\n", debugstr_a(valueA) );
3083 ptr = valueA;
3084 while (ptr)
3086 LPSTR next = strchr( ptr, ':' );
3087 if (next) *next++ = 0;
3088 ReadFontDir( ptr, TRUE );
3089 ptr = next;
3091 HeapFree( GetProcessHeap(), 0, valueA );
3093 HeapFree( GetProcessHeap(), 0, valueW );
3095 RegCloseKey(hkey);
3099 static BOOL move_to_front(const WCHAR *name)
3101 Family *family, *cursor2;
3102 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3104 if(!strcmpiW(family->FamilyName, name))
3106 list_remove(&family->entry);
3107 list_add_head(&font_list, &family->entry);
3108 return TRUE;
3111 return FALSE;
3114 static const WCHAR arial[] = {'A','r','i','a','l',0};
3115 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
3116 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};
3117 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};
3118 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
3119 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
3121 static void reorder_font_list(void)
3123 if(!move_to_front(times_new_roman))
3124 move_to_front(bitstream_vera_serif);
3126 if(!move_to_front(courier_new))
3127 move_to_front(bitstream_vera_sans_mono);
3129 if(!move_to_front(arial))
3130 move_to_front(bitstream_vera_sans);
3133 /*************************************************************
3134 * WineEngInit
3136 * Initialize FreeType library and create a list of available faces
3138 BOOL WineEngInit(void)
3140 HKEY hkey_font_cache;
3141 DWORD disposition;
3142 HANDLE font_mutex;
3144 /* update locale dependent font info in registry */
3145 update_font_info();
3147 if(!init_freetype()) return FALSE;
3149 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3151 ERR("Failed to create font mutex\n");
3152 return FALSE;
3154 WaitForSingleObject(font_mutex, INFINITE);
3156 create_font_cache_key(&hkey_font_cache, &disposition);
3158 if(disposition == REG_CREATED_NEW_KEY)
3159 init_font_list();
3160 else
3161 load_font_list_from_cache(hkey_font_cache);
3163 RegCloseKey(hkey_font_cache);
3165 reorder_font_list();
3167 DumpFontList();
3168 LoadSubstList();
3169 DumpSubstList();
3170 LoadReplaceList();
3172 if(disposition == REG_CREATED_NEW_KEY)
3173 update_reg_entries();
3175 update_system_links();
3176 init_system_links();
3178 ReleaseMutex(font_mutex);
3179 return TRUE;
3183 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3185 TT_OS2 *pOS2;
3186 TT_HoriHeader *pHori;
3188 LONG ppem;
3190 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3191 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3193 if(height == 0) height = 16;
3195 /* Calc. height of EM square:
3197 * For +ve lfHeight we have
3198 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3199 * Re-arranging gives:
3200 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3202 * For -ve lfHeight we have
3203 * |lfHeight| = ppem
3204 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3205 * with il = winAscent + winDescent - units_per_em]
3209 if(height > 0) {
3210 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3211 ppem = MulDiv(ft_face->units_per_EM, height,
3212 pHori->Ascender - pHori->Descender);
3213 else
3214 ppem = MulDiv(ft_face->units_per_EM, height,
3215 pOS2->usWinAscent + pOS2->usWinDescent);
3217 else
3218 ppem = -height;
3220 return ppem;
3223 static struct font_mapping *map_font_file( const char *name )
3225 struct font_mapping *mapping;
3226 struct stat st;
3227 int fd;
3229 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3230 if (fstat( fd, &st ) == -1) goto error;
3232 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3234 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3236 mapping->refcount++;
3237 close( fd );
3238 return mapping;
3241 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3242 goto error;
3244 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3245 close( fd );
3247 if (mapping->data == MAP_FAILED)
3249 HeapFree( GetProcessHeap(), 0, mapping );
3250 return NULL;
3252 mapping->refcount = 1;
3253 mapping->dev = st.st_dev;
3254 mapping->ino = st.st_ino;
3255 mapping->size = st.st_size;
3256 list_add_tail( &mappings_list, &mapping->entry );
3257 return mapping;
3259 error:
3260 close( fd );
3261 return NULL;
3264 static void unmap_font_file( struct font_mapping *mapping )
3266 if (!--mapping->refcount)
3268 list_remove( &mapping->entry );
3269 munmap( mapping->data, mapping->size );
3270 HeapFree( GetProcessHeap(), 0, mapping );
3274 static LONG load_VDMX(GdiFont*, LONG);
3276 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3278 FT_Error err;
3279 FT_Face ft_face;
3280 void *data_ptr;
3281 DWORD data_size;
3283 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3285 if (face->file)
3287 if (!(font->mapping = map_font_file( face->file )))
3289 WARN("failed to map %s\n", debugstr_a(face->file));
3290 return 0;
3292 data_ptr = font->mapping->data;
3293 data_size = font->mapping->size;
3295 else
3297 data_ptr = face->font_data_ptr;
3298 data_size = face->font_data_size;
3301 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3302 if(err) {
3303 ERR("FT_New_Face rets %d\n", err);
3304 return 0;
3307 /* set it here, as load_VDMX needs it */
3308 font->ft_face = ft_face;
3310 if(FT_IS_SCALABLE(ft_face)) {
3311 /* load the VDMX table if we have one */
3312 font->ppem = load_VDMX(font, height);
3313 if(font->ppem == 0)
3314 font->ppem = calc_ppem_for_height(ft_face, height);
3315 TRACE("height %d => ppem %d\n", height, font->ppem);
3317 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3318 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3319 } else {
3320 font->ppem = height;
3321 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3322 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3324 return ft_face;
3328 static int get_nearest_charset(Face *face, int *cp)
3330 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3331 a single face with the requested charset. The idea is to check if
3332 the selected font supports the current ANSI codepage, if it does
3333 return the corresponding charset, else return the first charset */
3335 CHARSETINFO csi;
3336 int acp = GetACP(), i;
3337 DWORD fs0;
3339 *cp = acp;
3340 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3341 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3342 return csi.ciCharset;
3344 for(i = 0; i < 32; i++) {
3345 fs0 = 1L << i;
3346 if(face->fs.fsCsb[0] & fs0) {
3347 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3348 *cp = csi.ciACP;
3349 return csi.ciCharset;
3351 else
3352 FIXME("TCI failing on %x\n", fs0);
3356 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3357 face->fs.fsCsb[0], face->file);
3358 *cp = acp;
3359 return DEFAULT_CHARSET;
3362 static GdiFont *alloc_font(void)
3364 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3365 ret->gmsize = 1;
3366 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3367 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3368 ret->potm = NULL;
3369 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3370 ret->total_kern_pairs = (DWORD)-1;
3371 ret->kern_pairs = NULL;
3372 list_init(&ret->hfontlist);
3373 list_init(&ret->child_fonts);
3374 return ret;
3377 static void free_font(GdiFont *font)
3379 struct list *cursor, *cursor2;
3380 DWORD i;
3382 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3384 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3385 list_remove(cursor);
3386 if(child->font)
3387 free_font(child->font);
3388 HeapFree(GetProcessHeap(), 0, child);
3391 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3393 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3394 DeleteObject(hfontlist->hfont);
3395 list_remove(&hfontlist->entry);
3396 HeapFree(GetProcessHeap(), 0, hfontlist);
3399 if (font->ft_face) pFT_Done_Face(font->ft_face);
3400 if (font->mapping) unmap_font_file( font->mapping );
3401 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3402 HeapFree(GetProcessHeap(), 0, font->potm);
3403 HeapFree(GetProcessHeap(), 0, font->name);
3404 for (i = 0; i < font->gmsize; i++)
3405 HeapFree(GetProcessHeap(),0,font->gm[i]);
3406 HeapFree(GetProcessHeap(), 0, font->gm);
3407 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3408 HeapFree(GetProcessHeap(), 0, font);
3412 /*************************************************************
3413 * load_VDMX
3415 * load the vdmx entry for the specified height
3418 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3419 ( ( (FT_ULong)_x4 << 24 ) | \
3420 ( (FT_ULong)_x3 << 16 ) | \
3421 ( (FT_ULong)_x2 << 8 ) | \
3422 (FT_ULong)_x1 )
3424 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3426 typedef struct {
3427 BYTE bCharSet;
3428 BYTE xRatio;
3429 BYTE yStartRatio;
3430 BYTE yEndRatio;
3431 } Ratios;
3433 typedef struct {
3434 WORD recs;
3435 BYTE startsz;
3436 BYTE endsz;
3437 } VDMX_group;
3439 static LONG load_VDMX(GdiFont *font, LONG height)
3441 WORD hdr[3], tmp;
3442 VDMX_group group;
3443 BYTE devXRatio, devYRatio;
3444 USHORT numRecs, numRatios;
3445 DWORD result, offset = -1;
3446 LONG ppem = 0;
3447 int i;
3449 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3451 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3452 return ppem;
3454 /* FIXME: need the real device aspect ratio */
3455 devXRatio = 1;
3456 devYRatio = 1;
3458 numRecs = GET_BE_WORD(hdr[1]);
3459 numRatios = GET_BE_WORD(hdr[2]);
3461 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3462 for(i = 0; i < numRatios; i++) {
3463 Ratios ratio;
3465 offset = (3 * 2) + (i * sizeof(Ratios));
3466 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3467 offset = -1;
3469 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3471 if((ratio.xRatio == 0 &&
3472 ratio.yStartRatio == 0 &&
3473 ratio.yEndRatio == 0) ||
3474 (devXRatio == ratio.xRatio &&
3475 devYRatio >= ratio.yStartRatio &&
3476 devYRatio <= ratio.yEndRatio))
3478 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3479 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3480 offset = GET_BE_WORD(tmp);
3481 break;
3485 if(offset == -1) {
3486 FIXME("No suitable ratio found\n");
3487 return ppem;
3490 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3491 USHORT recs;
3492 BYTE startsz, endsz;
3493 WORD *vTable;
3495 recs = GET_BE_WORD(group.recs);
3496 startsz = group.startsz;
3497 endsz = group.endsz;
3499 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3501 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3502 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3503 if(result == GDI_ERROR) {
3504 FIXME("Failed to retrieve vTable\n");
3505 goto end;
3508 if(height > 0) {
3509 for(i = 0; i < recs; i++) {
3510 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3511 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3512 ppem = GET_BE_WORD(vTable[i * 3]);
3514 if(yMax + -yMin == height) {
3515 font->yMax = yMax;
3516 font->yMin = yMin;
3517 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3518 break;
3520 if(yMax + -yMin > height) {
3521 if(--i < 0) {
3522 ppem = 0;
3523 goto end; /* failed */
3525 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3526 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3527 ppem = GET_BE_WORD(vTable[i * 3]);
3528 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3529 break;
3532 if(!font->yMax) {
3533 ppem = 0;
3534 TRACE("ppem not found for height %d\n", height);
3537 end:
3538 HeapFree(GetProcessHeap(), 0, vTable);
3541 return ppem;
3544 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3546 if(font->font_desc.hash != fd->hash) return TRUE;
3547 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3548 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3549 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3550 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3553 static void calc_hash(FONT_DESC *pfd)
3555 DWORD hash = 0, *ptr, two_chars;
3556 WORD *pwc;
3557 unsigned int i;
3559 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3560 hash ^= *ptr;
3561 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3562 hash ^= *ptr;
3563 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3564 two_chars = *ptr;
3565 pwc = (WCHAR *)&two_chars;
3566 if(!*pwc) break;
3567 *pwc = toupperW(*pwc);
3568 pwc++;
3569 *pwc = toupperW(*pwc);
3570 hash ^= two_chars;
3571 if(!*pwc) break;
3573 hash ^= !pfd->can_use_bitmap;
3574 pfd->hash = hash;
3575 return;
3578 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3580 GdiFont *ret;
3581 FONT_DESC fd;
3582 HFONTLIST *hflist;
3583 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3585 fd.lf = *plf;
3586 fd.matrix = *pmat;
3587 fd.can_use_bitmap = can_use_bitmap;
3588 calc_hash(&fd);
3590 /* try the child list */
3591 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3592 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3593 if(!fontcmp(ret, &fd)) {
3594 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3595 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3596 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3597 if(hflist->hfont == hfont)
3598 return ret;
3603 /* try the in-use list */
3604 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3605 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3606 if(!fontcmp(ret, &fd)) {
3607 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3608 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3609 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3610 if(hflist->hfont == hfont)
3611 return ret;
3613 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3614 hflist->hfont = hfont;
3615 list_add_head(&ret->hfontlist, &hflist->entry);
3616 return ret;
3620 /* then the unused list */
3621 font_elem_ptr = list_head(&unused_gdi_font_list);
3622 while(font_elem_ptr) {
3623 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3624 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3625 if(!fontcmp(ret, &fd)) {
3626 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3627 assert(list_empty(&ret->hfontlist));
3628 TRACE("Found %p in unused list\n", ret);
3629 list_remove(&ret->entry);
3630 list_add_head(&gdi_font_list, &ret->entry);
3631 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3632 hflist->hfont = hfont;
3633 list_add_head(&ret->hfontlist, &hflist->entry);
3634 return ret;
3637 return NULL;
3640 static void add_to_cache(GdiFont *font)
3642 static DWORD cache_num = 1;
3644 font->cache_num = cache_num++;
3645 list_add_head(&gdi_font_list, &font->entry);
3648 /*************************************************************
3649 * create_child_font_list
3651 static BOOL create_child_font_list(GdiFont *font)
3653 BOOL ret = FALSE;
3654 SYSTEM_LINKS *font_link;
3655 CHILD_FONT *font_link_entry, *new_child;
3656 FontSubst *psub;
3657 WCHAR* font_name;
3659 psub = get_font_subst(&font_subst_list, font->name, -1);
3660 font_name = psub ? psub->to.name : font->name;
3661 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3663 if(!strcmpiW(font_link->font_name, font_name))
3665 TRACE("found entry in system list\n");
3666 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3668 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3669 new_child->face = font_link_entry->face;
3670 new_child->font = NULL;
3671 list_add_tail(&font->child_fonts, &new_child->entry);
3672 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3674 ret = TRUE;
3675 break;
3679 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3680 * Sans Serif. This is how asian windows get default fallbacks for fonts
3682 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3683 font->charset != OEM_CHARSET &&
3684 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3685 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3687 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3689 TRACE("found entry in default fallback list\n");
3690 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3692 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3693 new_child->face = font_link_entry->face;
3694 new_child->font = NULL;
3695 list_add_tail(&font->child_fonts, &new_child->entry);
3696 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3698 ret = TRUE;
3699 break;
3703 return ret;
3706 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3708 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3710 if (pFT_Set_Charmap)
3712 FT_Int i;
3713 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3715 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3717 for (i = 0; i < ft_face->num_charmaps; i++)
3719 if (ft_face->charmaps[i]->encoding == encoding)
3721 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3722 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3724 switch (ft_face->charmaps[i]->platform_id)
3726 default:
3727 cmap_def = ft_face->charmaps[i];
3728 break;
3729 case 0: /* Apple Unicode */
3730 cmap0 = ft_face->charmaps[i];
3731 break;
3732 case 1: /* Macintosh */
3733 cmap1 = ft_face->charmaps[i];
3734 break;
3735 case 2: /* ISO */
3736 cmap2 = ft_face->charmaps[i];
3737 break;
3738 case 3: /* Microsoft */
3739 cmap3 = ft_face->charmaps[i];
3740 break;
3744 if (cmap3) /* prefer Microsoft cmap table */
3745 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3746 else if (cmap1)
3747 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3748 else if (cmap2)
3749 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3750 else if (cmap0)
3751 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3752 else if (cmap_def)
3753 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3755 return ft_err == FT_Err_Ok;
3758 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3761 /*************************************************************
3762 * WineEngCreateFontInstance
3765 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3767 GdiFont *ret;
3768 Face *face, *best, *best_bitmap;
3769 Family *family, *last_resort_family;
3770 struct list *family_elem_ptr, *face_elem_ptr;
3771 INT height, width = 0;
3772 unsigned int score = 0, new_score;
3773 signed int diff = 0, newdiff;
3774 BOOL bd, it, can_use_bitmap;
3775 LOGFONTW lf;
3776 CHARSETINFO csi;
3777 HFONTLIST *hflist;
3778 FMAT2 dcmat;
3779 FontSubst *psub = NULL;
3781 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3782 lf.lfWidth = abs(lf.lfWidth);
3784 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3786 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3787 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3788 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3789 lf.lfEscapement);
3791 if(dc->GraphicsMode == GM_ADVANCED)
3792 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3793 else
3795 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3796 font scaling abilities. */
3797 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3798 dcmat.eM21 = dcmat.eM12 = 0;
3801 /* Try to avoid not necessary glyph transformations */
3802 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3804 lf.lfHeight *= fabs(dcmat.eM11);
3805 lf.lfWidth *= fabs(dcmat.eM11);
3806 dcmat.eM11 = dcmat.eM22 = 1.0;
3809 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3810 dcmat.eM21, dcmat.eM22);
3812 GDI_CheckNotLock();
3813 EnterCriticalSection( &freetype_cs );
3815 /* check the cache first */
3816 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3817 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3818 LeaveCriticalSection( &freetype_cs );
3819 return ret;
3822 TRACE("not in cache\n");
3823 if(list_empty(&font_list)) /* No fonts installed */
3825 TRACE("No fonts installed\n");
3826 LeaveCriticalSection( &freetype_cs );
3827 return NULL;
3830 ret = alloc_font();
3832 ret->font_desc.matrix = dcmat;
3833 ret->font_desc.lf = lf;
3834 ret->font_desc.can_use_bitmap = can_use_bitmap;
3835 calc_hash(&ret->font_desc);
3836 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3837 hflist->hfont = hfont;
3838 list_add_head(&ret->hfontlist, &hflist->entry);
3840 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3841 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3842 original value lfCharSet. Note this is a special case for
3843 Symbol and doesn't happen at least for "Wingdings*" */
3845 if(!strcmpiW(lf.lfFaceName, SymbolW))
3846 lf.lfCharSet = SYMBOL_CHARSET;
3848 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3849 switch(lf.lfCharSet) {
3850 case DEFAULT_CHARSET:
3851 csi.fs.fsCsb[0] = 0;
3852 break;
3853 default:
3854 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3855 csi.fs.fsCsb[0] = 0;
3856 break;
3860 family = NULL;
3861 if(lf.lfFaceName[0] != '\0') {
3862 SYSTEM_LINKS *font_link;
3863 CHILD_FONT *font_link_entry;
3864 LPWSTR FaceName = lf.lfFaceName;
3867 * Check for a leading '@' this signals that the font is being
3868 * requested in tategaki mode (vertical writing substitution) but
3869 * does not affect the fontface that is to be selected.
3871 if (lf.lfFaceName[0]=='@')
3872 FaceName = &lf.lfFaceName[1];
3874 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3876 if(psub) {
3877 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3878 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3879 if (psub->to.charset != -1)
3880 lf.lfCharSet = psub->to.charset;
3883 /* We want a match on name and charset or just name if
3884 charset was DEFAULT_CHARSET. If the latter then
3885 we fixup the returned charset later in get_nearest_charset
3886 where we'll either use the charset of the current ansi codepage
3887 or if that's unavailable the first charset that the font supports.
3889 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3890 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3891 if (!strcmpiW(family->FamilyName, FaceName) ||
3892 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3894 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3895 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3896 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3897 if(face->scalable || can_use_bitmap)
3898 goto found;
3903 /* Search by full face name. */
3904 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3905 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3906 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3907 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3908 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3909 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3911 if(face->scalable || can_use_bitmap)
3912 goto found_face;
3918 * Try check the SystemLink list first for a replacement font.
3919 * We may find good replacements there.
3921 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3923 if(!strcmpiW(font_link->font_name, FaceName) ||
3924 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3926 TRACE("found entry in system list\n");
3927 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3929 face = font_link_entry->face;
3930 family = face->family;
3931 if(csi.fs.fsCsb[0] &
3932 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3934 if(face->scalable || can_use_bitmap)
3935 goto found;
3942 psub = NULL; /* substitution is no more relevant */
3944 /* If requested charset was DEFAULT_CHARSET then try using charset
3945 corresponding to the current ansi codepage */
3946 if (!csi.fs.fsCsb[0])
3948 INT acp = GetACP();
3949 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3950 FIXME("TCI failed on codepage %d\n", acp);
3951 csi.fs.fsCsb[0] = 0;
3952 } else
3953 lf.lfCharSet = csi.ciCharset;
3956 /* Face families are in the top 4 bits of lfPitchAndFamily,
3957 so mask with 0xF0 before testing */
3959 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3960 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3961 strcpyW(lf.lfFaceName, defFixed);
3962 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3963 strcpyW(lf.lfFaceName, defSerif);
3964 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3965 strcpyW(lf.lfFaceName, defSans);
3966 else
3967 strcpyW(lf.lfFaceName, defSans);
3968 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3969 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3970 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3971 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3972 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3973 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3974 if(face->scalable || can_use_bitmap)
3975 goto found;
3980 last_resort_family = NULL;
3981 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3982 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3983 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3984 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3985 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3986 if(face->scalable)
3987 goto found;
3988 if(can_use_bitmap && !last_resort_family)
3989 last_resort_family = family;
3994 if(last_resort_family) {
3995 family = last_resort_family;
3996 csi.fs.fsCsb[0] = 0;
3997 goto found;
4000 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4001 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4002 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4003 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4004 if(face->scalable) {
4005 csi.fs.fsCsb[0] = 0;
4006 WARN("just using first face for now\n");
4007 goto found;
4009 if(can_use_bitmap && !last_resort_family)
4010 last_resort_family = family;
4013 if(!last_resort_family) {
4014 FIXME("can't find a single appropriate font - bailing\n");
4015 free_font(ret);
4016 LeaveCriticalSection( &freetype_cs );
4017 return NULL;
4020 WARN("could only find a bitmap font - this will probably look awful!\n");
4021 family = last_resort_family;
4022 csi.fs.fsCsb[0] = 0;
4024 found:
4025 it = lf.lfItalic ? 1 : 0;
4026 bd = lf.lfWeight > 550 ? 1 : 0;
4028 height = lf.lfHeight;
4030 face = best = best_bitmap = NULL;
4031 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4033 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4035 BOOL italic, bold;
4037 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4038 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4039 new_score = (italic ^ it) + (bold ^ bd);
4040 if(!best || new_score <= score)
4042 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4043 italic, bold, it, bd);
4044 score = new_score;
4045 best = face;
4046 if(best->scalable && score == 0) break;
4047 if(!best->scalable)
4049 if(height > 0)
4050 newdiff = height - (signed int)(best->size.height);
4051 else
4052 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4053 if(!best_bitmap || new_score < score ||
4054 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4056 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4057 diff = newdiff;
4058 best_bitmap = best;
4059 if(score == 0 && diff == 0) break;
4065 if(best)
4066 face = best->scalable ? best : best_bitmap;
4067 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4068 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4070 found_face:
4071 height = lf.lfHeight;
4073 ret->fs = face->fs;
4075 if(csi.fs.fsCsb[0]) {
4076 ret->charset = lf.lfCharSet;
4077 ret->codepage = csi.ciACP;
4079 else
4080 ret->charset = get_nearest_charset(face, &ret->codepage);
4082 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4083 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4085 ret->aveWidth = height ? lf.lfWidth : 0;
4087 if(!face->scalable) {
4088 /* Windows uses integer scaling factors for bitmap fonts */
4089 INT scale, scaled_height;
4090 GdiFont *cachedfont;
4092 /* FIXME: rotation of bitmap fonts is ignored */
4093 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4094 if (ret->aveWidth)
4095 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4096 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4097 dcmat.eM11 = dcmat.eM22 = 1.0;
4098 /* As we changed the matrix, we need to search the cache for the font again,
4099 * otherwise we might explode the cache. */
4100 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4101 TRACE("Found cached font after non-scalable matrix rescale!\n");
4102 free_font( ret );
4103 LeaveCriticalSection( &freetype_cs );
4104 return cachedfont;
4106 calc_hash(&ret->font_desc);
4108 if (height != 0) height = diff;
4109 height += face->size.height;
4111 scale = (height + face->size.height - 1) / face->size.height;
4112 scaled_height = scale * face->size.height;
4113 /* Only jump to the next height if the difference <= 25% original height */
4114 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4115 /* The jump between unscaled and doubled is delayed by 1 */
4116 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4117 ret->scale_y = scale;
4119 width = face->size.x_ppem >> 6;
4120 height = face->size.y_ppem >> 6;
4122 else
4123 ret->scale_y = 1.0;
4124 TRACE("font scale y: %f\n", ret->scale_y);
4126 ret->ft_face = OpenFontFace(ret, face, width, height);
4128 if (!ret->ft_face)
4130 free_font( ret );
4131 LeaveCriticalSection( &freetype_cs );
4132 return 0;
4135 ret->ntmFlags = face->ntmFlags;
4137 if (ret->charset == SYMBOL_CHARSET &&
4138 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4139 /* No ops */
4141 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4142 /* No ops */
4144 else {
4145 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4148 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4149 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4150 ret->underline = lf.lfUnderline ? 0xff : 0;
4151 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4152 create_child_font_list(ret);
4154 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4156 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
4157 if (length != GDI_ERROR)
4159 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4160 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4161 TRACE("Loaded GSUB table of %i bytes\n",length);
4165 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4167 add_to_cache(ret);
4168 LeaveCriticalSection( &freetype_cs );
4169 return ret;
4172 static void dump_gdi_font_list(void)
4174 GdiFont *gdiFont;
4175 struct list *elem_ptr;
4177 TRACE("---------- gdiFont Cache ----------\n");
4178 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4179 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4180 TRACE("gdiFont=%p %s %d\n",
4181 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4184 TRACE("---------- Unused gdiFont Cache ----------\n");
4185 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4186 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4187 TRACE("gdiFont=%p %s %d\n",
4188 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4191 TRACE("---------- Child gdiFont Cache ----------\n");
4192 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4193 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4194 TRACE("gdiFont=%p %s %d\n",
4195 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4199 /*************************************************************
4200 * WineEngDestroyFontInstance
4202 * free the gdiFont associated with this handle
4205 BOOL WineEngDestroyFontInstance(HFONT handle)
4207 GdiFont *gdiFont;
4208 HFONTLIST *hflist;
4209 BOOL ret = FALSE;
4210 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4211 int i = 0;
4213 GDI_CheckNotLock();
4214 EnterCriticalSection( &freetype_cs );
4216 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4218 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4219 while(hfontlist_elem_ptr) {
4220 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4221 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4222 if(hflist->hfont == handle) {
4223 TRACE("removing child font %p from child list\n", gdiFont);
4224 list_remove(&gdiFont->entry);
4225 LeaveCriticalSection( &freetype_cs );
4226 return TRUE;
4231 TRACE("destroying hfont=%p\n", handle);
4232 if(TRACE_ON(font))
4233 dump_gdi_font_list();
4235 font_elem_ptr = list_head(&gdi_font_list);
4236 while(font_elem_ptr) {
4237 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4238 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4240 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4241 while(hfontlist_elem_ptr) {
4242 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4243 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4244 if(hflist->hfont == handle) {
4245 list_remove(&hflist->entry);
4246 HeapFree(GetProcessHeap(), 0, hflist);
4247 ret = TRUE;
4250 if(list_empty(&gdiFont->hfontlist)) {
4251 TRACE("Moving to Unused list\n");
4252 list_remove(&gdiFont->entry);
4253 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4258 font_elem_ptr = list_head(&unused_gdi_font_list);
4259 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4260 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4261 while(font_elem_ptr) {
4262 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4263 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4264 TRACE("freeing %p\n", gdiFont);
4265 list_remove(&gdiFont->entry);
4266 free_font(gdiFont);
4268 LeaveCriticalSection( &freetype_cs );
4269 return ret;
4272 /***************************************************
4273 * create_enum_charset_list
4275 * This function creates charset enumeration list because in DEFAULT_CHARSET
4276 * case, the ANSI codepage's charset takes precedence over other charsets.
4277 * This function works as a filter other than DEFAULT_CHARSET case.
4279 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4281 CHARSETINFO csi;
4282 DWORD n = 0;
4284 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4285 csi.fs.fsCsb[0] != 0) {
4286 list->element[n].mask = csi.fs.fsCsb[0];
4287 list->element[n].charset = csi.ciCharset;
4288 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4289 n++;
4291 else { /* charset is DEFAULT_CHARSET or invalid. */
4292 INT acp, i;
4294 /* Set the current codepage's charset as the first element. */
4295 acp = GetACP();
4296 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4297 csi.fs.fsCsb[0] != 0) {
4298 list->element[n].mask = csi.fs.fsCsb[0];
4299 list->element[n].charset = csi.ciCharset;
4300 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4301 n++;
4304 /* Fill out left elements. */
4305 for (i = 0; i < 32; i++) {
4306 FONTSIGNATURE fs;
4307 fs.fsCsb[0] = 1L << i;
4308 fs.fsCsb[1] = 0;
4309 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4310 continue; /* skip, already added. */
4311 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4312 continue; /* skip, this is an invalid fsCsb bit. */
4314 list->element[n].mask = fs.fsCsb[0];
4315 list->element[n].charset = csi.ciCharset;
4316 list->element[n].name = ElfScriptsW[i];
4317 n++;
4320 list->total = n;
4322 return n;
4325 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4326 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4328 GdiFont *font;
4329 LONG width, height;
4331 if (face->cached_enum_data)
4333 TRACE("Cached\n");
4334 *pelf = face->cached_enum_data->elf;
4335 *pntm = face->cached_enum_data->ntm;
4336 *ptype = face->cached_enum_data->type;
4337 return;
4340 font = alloc_font();
4342 if(face->scalable) {
4343 height = -2048; /* 2048 is the most common em size */
4344 width = 0;
4345 } else {
4346 height = face->size.y_ppem >> 6;
4347 width = face->size.x_ppem >> 6;
4349 font->scale_y = 1.0;
4351 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4353 free_font(font);
4354 return;
4357 font->name = strdupW(face->family->FamilyName);
4358 font->ntmFlags = face->ntmFlags;
4360 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4362 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4364 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4366 lstrcpynW(pelf->elfLogFont.lfFaceName,
4367 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4368 LF_FACESIZE);
4369 lstrcpynW(pelf->elfFullName,
4370 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4371 LF_FULLFACESIZE);
4372 lstrcpynW(pelf->elfStyle,
4373 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4374 LF_FACESIZE);
4376 else
4378 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4380 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4382 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4383 if (face->FullName)
4384 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4385 else
4386 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4387 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4390 pntm->ntmTm.ntmFlags = face->ntmFlags;
4391 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4392 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4393 pntm->ntmFontSig = face->fs;
4395 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4397 pelf->elfLogFont.lfEscapement = 0;
4398 pelf->elfLogFont.lfOrientation = 0;
4399 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4400 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4401 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4402 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4403 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4404 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4405 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4406 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4407 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4408 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4409 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4411 *ptype = 0;
4412 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4413 *ptype |= TRUETYPE_FONTTYPE;
4414 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4415 *ptype |= DEVICE_FONTTYPE;
4416 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4417 *ptype |= RASTER_FONTTYPE;
4419 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4420 if (face->cached_enum_data)
4422 face->cached_enum_data->elf = *pelf;
4423 face->cached_enum_data->ntm = *pntm;
4424 face->cached_enum_data->type = *ptype;
4427 free_font(font);
4430 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4432 struct list *face_elem_ptr;
4434 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4436 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4438 static const WCHAR spaceW[] = { ' ',0 };
4439 WCHAR full_family_name[LF_FULLFACESIZE];
4440 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4442 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4444 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4445 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4446 continue;
4449 strcpyW(full_family_name, family->FamilyName);
4450 strcatW(full_family_name, spaceW);
4451 strcatW(full_family_name, face->StyleName);
4452 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4455 return FALSE;
4458 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4460 static const WCHAR spaceW[] = { ' ',0 };
4461 WCHAR full_family_name[LF_FULLFACESIZE];
4463 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4465 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4467 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4468 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4469 return FALSE;
4472 strcpyW(full_family_name, face->family->FamilyName);
4473 strcatW(full_family_name, spaceW);
4474 strcatW(full_family_name, face->StyleName);
4475 return !strcmpiW(lf->lfFaceName, full_family_name);
4478 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4479 FONTENUMPROCW proc, LPARAM lparam)
4481 ENUMLOGFONTEXW elf;
4482 NEWTEXTMETRICEXW ntm;
4483 DWORD type = 0;
4484 int i;
4486 GetEnumStructs(face, &elf, &ntm, &type);
4487 for(i = 0; i < list->total; i++) {
4488 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4489 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4490 strcpyW(elf.elfScript, OEM_DOSW);
4491 i = 32; /* break out of loop */
4492 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4493 continue;
4494 else {
4495 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4496 if(list->element[i].name)
4497 strcpyW(elf.elfScript, list->element[i].name);
4498 else
4499 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4501 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4502 debugstr_w(elf.elfLogFont.lfFaceName),
4503 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4504 list->element[i].charset, type, debugstr_w(elf.elfScript),
4505 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4506 ntm.ntmTm.ntmFlags);
4507 /* release section before callback (FIXME) */
4508 LeaveCriticalSection( &freetype_cs );
4509 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4510 EnterCriticalSection( &freetype_cs );
4512 return TRUE;
4515 /*************************************************************
4516 * WineEngEnumFonts
4519 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4521 Family *family;
4522 Face *face;
4523 struct list *family_elem_ptr, *face_elem_ptr;
4524 LOGFONTW lf;
4525 struct enum_charset_list enum_charsets;
4527 if (!plf)
4529 lf.lfCharSet = DEFAULT_CHARSET;
4530 lf.lfPitchAndFamily = 0;
4531 lf.lfFaceName[0] = 0;
4532 plf = &lf;
4535 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4537 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4539 GDI_CheckNotLock();
4540 EnterCriticalSection( &freetype_cs );
4541 if(plf->lfFaceName[0]) {
4542 FontSubst *psub;
4543 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4545 if(psub) {
4546 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4547 debugstr_w(psub->to.name));
4548 lf = *plf;
4549 strcpyW(lf.lfFaceName, psub->to.name);
4550 plf = &lf;
4553 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4554 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4555 if(family_matches(family, plf)) {
4556 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4557 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4558 if (!face_matches(face, plf)) continue;
4559 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4563 } else {
4564 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4565 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4566 face_elem_ptr = list_head(&family->faces);
4567 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4568 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4571 LeaveCriticalSection( &freetype_cs );
4572 return 1;
4575 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4577 pt->x.value = vec->x >> 6;
4578 pt->x.fract = (vec->x & 0x3f) << 10;
4579 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4580 pt->y.value = vec->y >> 6;
4581 pt->y.fract = (vec->y & 0x3f) << 10;
4582 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4583 return;
4586 /***************************************************
4587 * According to the MSDN documentation on WideCharToMultiByte,
4588 * certain codepages cannot set the default_used parameter.
4589 * This returns TRUE if the codepage can set that parameter, false else
4590 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4592 static BOOL codepage_sets_default_used(UINT codepage)
4594 switch (codepage)
4596 case CP_UTF7:
4597 case CP_UTF8:
4598 case CP_SYMBOL:
4599 return FALSE;
4600 default:
4601 return TRUE;
4606 * GSUB Table handling functions
4609 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4611 const GSUB_CoverageFormat1* cf1;
4613 cf1 = table;
4615 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4617 int count = GET_BE_WORD(cf1->GlyphCount);
4618 int i;
4619 TRACE("Coverage Format 1, %i glyphs\n",count);
4620 for (i = 0; i < count; i++)
4621 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4622 return i;
4623 return -1;
4625 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4627 const GSUB_CoverageFormat2* cf2;
4628 int i;
4629 int count;
4630 cf2 = (const GSUB_CoverageFormat2*)cf1;
4632 count = GET_BE_WORD(cf2->RangeCount);
4633 TRACE("Coverage Format 2, %i ranges\n",count);
4634 for (i = 0; i < count; i++)
4636 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4637 return -1;
4638 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4639 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4641 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4642 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4645 return -1;
4647 else
4648 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4650 return -1;
4653 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4655 const GSUB_ScriptList *script;
4656 const GSUB_Script *deflt = NULL;
4657 int i;
4658 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4660 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4661 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4663 const GSUB_Script *scr;
4664 int offset;
4666 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4667 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4669 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4670 return scr;
4671 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4672 deflt = scr;
4674 return deflt;
4677 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4679 int i;
4680 int offset;
4681 const GSUB_LangSys *Lang;
4683 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4685 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4687 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4688 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4690 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4691 return Lang;
4693 offset = GET_BE_WORD(script->DefaultLangSys);
4694 if (offset)
4696 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4697 return Lang;
4699 return NULL;
4702 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4704 int i;
4705 const GSUB_FeatureList *feature;
4706 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4708 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4709 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4711 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4712 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4714 const GSUB_Feature *feat;
4715 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4716 return feat;
4719 return NULL;
4722 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4724 int i;
4725 int offset;
4726 const GSUB_LookupList *lookup;
4727 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4729 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4730 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4732 const GSUB_LookupTable *look;
4733 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4734 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4735 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4736 if (GET_BE_WORD(look->LookupType) != 1)
4737 FIXME("We only handle SubType 1\n");
4738 else
4740 int j;
4742 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4744 const GSUB_SingleSubstFormat1 *ssf1;
4745 offset = GET_BE_WORD(look->SubTable[j]);
4746 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4747 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4749 int offset = GET_BE_WORD(ssf1->Coverage);
4750 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4751 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4753 TRACE(" Glyph 0x%x ->",glyph);
4754 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4755 TRACE(" 0x%x\n",glyph);
4758 else
4760 const GSUB_SingleSubstFormat2 *ssf2;
4761 INT index;
4762 INT offset;
4764 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4765 offset = GET_BE_WORD(ssf1->Coverage);
4766 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4767 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4768 TRACE(" Coverage index %i\n",index);
4769 if (index != -1)
4771 TRACE(" Glyph is 0x%x ->",glyph);
4772 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4773 TRACE("0x%x\n",glyph);
4779 return glyph;
4782 static const char* get_opentype_script(const GdiFont *font)
4785 * I am not sure if this is the correct way to generate our script tag
4788 switch (font->charset)
4790 case ANSI_CHARSET: return "latn";
4791 case BALTIC_CHARSET: return "latn"; /* ?? */
4792 case CHINESEBIG5_CHARSET: return "hani";
4793 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4794 case GB2312_CHARSET: return "hani";
4795 case GREEK_CHARSET: return "grek";
4796 case HANGUL_CHARSET: return "hang";
4797 case RUSSIAN_CHARSET: return "cyrl";
4798 case SHIFTJIS_CHARSET: return "kana";
4799 case TURKISH_CHARSET: return "latn"; /* ?? */
4800 case VIETNAMESE_CHARSET: return "latn";
4801 case JOHAB_CHARSET: return "latn"; /* ?? */
4802 case ARABIC_CHARSET: return "arab";
4803 case HEBREW_CHARSET: return "hebr";
4804 case THAI_CHARSET: return "thai";
4805 default: return "latn";
4809 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4811 const GSUB_Header *header;
4812 const GSUB_Script *script;
4813 const GSUB_LangSys *language;
4814 const GSUB_Feature *feature;
4816 if (!font->GSUB_Table)
4817 return glyph;
4819 header = font->GSUB_Table;
4821 script = GSUB_get_script_table(header, get_opentype_script(font));
4822 if (!script)
4824 TRACE("Script not found\n");
4825 return glyph;
4827 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4828 if (!language)
4830 TRACE("Language not found\n");
4831 return glyph;
4833 feature = GSUB_get_feature(header, language, "vrt2");
4834 if (!feature)
4835 feature = GSUB_get_feature(header, language, "vert");
4836 if (!feature)
4838 TRACE("vrt2/vert feature not found\n");
4839 return glyph;
4841 return GSUB_apply_feature(header, feature, glyph);
4844 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4846 FT_UInt glyphId;
4848 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4849 WCHAR wc = (WCHAR)glyph;
4850 BOOL default_used;
4851 BOOL *default_used_pointer;
4852 FT_UInt ret;
4853 char buf;
4854 default_used_pointer = NULL;
4855 default_used = FALSE;
4856 if (codepage_sets_default_used(font->codepage))
4857 default_used_pointer = &default_used;
4858 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4859 ret = 0;
4860 else
4861 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4862 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4863 return get_GSUB_vert_glyph(font,ret);
4866 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4868 if (glyph < 0x100) glyph += 0xf000;
4869 /* there is a number of old pre-Unicode "broken" TTFs, which
4870 do have symbols at U+00XX instead of U+f0XX */
4871 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4872 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4874 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4876 return get_GSUB_vert_glyph(font,glyphId);
4879 /*************************************************************
4880 * WineEngGetGlyphIndices
4883 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4884 LPWORD pgi, DWORD flags)
4886 int i;
4887 WORD default_char;
4888 BOOL got_default = FALSE;
4890 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4892 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4893 got_default = TRUE;
4896 for(i = 0; i < count; i++)
4898 pgi[i] = get_glyph_index(font, lpstr[i]);
4899 if (pgi[i] == 0)
4901 if (!got_default)
4903 if (FT_IS_SFNT(font->ft_face))
4905 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4906 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4908 else
4910 TEXTMETRICW textm;
4911 WineEngGetTextMetrics(font, &textm);
4912 default_char = textm.tmDefaultChar;
4914 got_default = TRUE;
4916 pgi[i] = default_char;
4919 return count;
4922 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4924 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4925 return !memcmp(matrix, &identity, sizeof(FMAT2));
4928 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4930 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4931 return !memcmp(matrix, &identity, sizeof(MAT2));
4934 /*************************************************************
4935 * WineEngGetGlyphOutline
4937 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4938 * except that the first parameter is the HWINEENGFONT of the font in
4939 * question rather than an HDC.
4942 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4943 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4944 const MAT2* lpmat)
4946 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4947 FT_Face ft_face = incoming_font->ft_face;
4948 GdiFont *font = incoming_font;
4949 FT_UInt glyph_index;
4950 DWORD width, height, pitch, needed = 0;
4951 FT_Bitmap ft_bitmap;
4952 FT_Error err;
4953 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4954 FT_Angle angle = 0;
4955 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4956 double widthRatio = 1.0;
4957 FT_Matrix transMat = identityMat;
4958 FT_Matrix transMatUnrotated;
4959 BOOL needsTransform = FALSE;
4960 BOOL tategaki = (font->GSUB_Table != NULL);
4961 UINT original_index;
4963 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4964 buflen, buf, lpmat);
4966 TRACE("font transform %f %f %f %f\n",
4967 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4968 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4970 GDI_CheckNotLock();
4971 EnterCriticalSection( &freetype_cs );
4973 if(format & GGO_GLYPH_INDEX) {
4974 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4975 original_index = glyph;
4976 format &= ~GGO_GLYPH_INDEX;
4977 } else {
4978 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4979 ft_face = font->ft_face;
4980 original_index = glyph_index;
4983 if(format & GGO_UNHINTED) {
4984 load_flags |= FT_LOAD_NO_HINTING;
4985 format &= ~GGO_UNHINTED;
4988 /* tategaki never appears to happen to lower glyph index */
4989 if (glyph_index < TATEGAKI_LOWER_BOUND )
4990 tategaki = FALSE;
4992 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4993 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4994 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4995 font->gmsize * sizeof(GM*));
4996 } else {
4997 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4998 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5000 *lpgm = FONT_GM(font,original_index)->gm;
5001 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5002 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5003 lpgm->gmCellIncX, lpgm->gmCellIncY);
5004 LeaveCriticalSection( &freetype_cs );
5005 return 1; /* FIXME */
5009 if (!font->gm[original_index / GM_BLOCK_SIZE])
5010 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5012 /* Scaling factor */
5013 if (font->aveWidth)
5015 TEXTMETRICW tm;
5017 WineEngGetTextMetrics(font, &tm);
5019 widthRatio = (double)font->aveWidth;
5020 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5022 else
5023 widthRatio = font->scale_y;
5025 /* Scaling transform */
5026 if (widthRatio != 1.0 || font->scale_y != 1.0)
5028 FT_Matrix scaleMat;
5029 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5030 scaleMat.xy = 0;
5031 scaleMat.yx = 0;
5032 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5034 pFT_Matrix_Multiply(&scaleMat, &transMat);
5035 needsTransform = TRUE;
5038 /* Slant transform */
5039 if (font->fake_italic) {
5040 FT_Matrix slantMat;
5042 slantMat.xx = (1 << 16);
5043 slantMat.xy = ((1 << 16) >> 2);
5044 slantMat.yx = 0;
5045 slantMat.yy = (1 << 16);
5046 pFT_Matrix_Multiply(&slantMat, &transMat);
5047 needsTransform = TRUE;
5050 /* Rotation transform */
5051 transMatUnrotated = transMat;
5052 if(font->orientation && !tategaki) {
5053 FT_Matrix rotationMat;
5054 FT_Vector vecAngle;
5055 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5056 pFT_Vector_Unit(&vecAngle, angle);
5057 rotationMat.xx = vecAngle.x;
5058 rotationMat.xy = -vecAngle.y;
5059 rotationMat.yx = -rotationMat.xy;
5060 rotationMat.yy = rotationMat.xx;
5062 pFT_Matrix_Multiply(&rotationMat, &transMat);
5063 needsTransform = TRUE;
5066 /* World transform */
5067 if (!is_identity_FMAT2(&font->font_desc.matrix))
5069 FT_Matrix worldMat;
5070 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5071 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5072 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5073 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5074 pFT_Matrix_Multiply(&worldMat, &transMat);
5075 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5076 needsTransform = TRUE;
5079 /* Extra transformation specified by caller */
5080 if (!is_identity_MAT2(lpmat))
5082 FT_Matrix extraMat;
5083 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5084 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5085 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5086 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5087 pFT_Matrix_Multiply(&extraMat, &transMat);
5088 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5089 needsTransform = TRUE;
5092 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5093 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5094 format == GGO_GRAY8_BITMAP))
5096 load_flags |= FT_LOAD_NO_BITMAP;
5099 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5101 if(err) {
5102 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5103 LeaveCriticalSection( &freetype_cs );
5104 return GDI_ERROR;
5107 if(!needsTransform) {
5108 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5109 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5110 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5112 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5113 bottom = (ft_face->glyph->metrics.horiBearingY -
5114 ft_face->glyph->metrics.height) & -64;
5115 lpgm->gmCellIncX = adv;
5116 lpgm->gmCellIncY = 0;
5117 } else {
5118 INT xc, yc;
5119 FT_Vector vec;
5121 left = right = 0;
5123 for(xc = 0; xc < 2; xc++) {
5124 for(yc = 0; yc < 2; yc++) {
5125 vec.x = (ft_face->glyph->metrics.horiBearingX +
5126 xc * ft_face->glyph->metrics.width);
5127 vec.y = ft_face->glyph->metrics.horiBearingY -
5128 yc * ft_face->glyph->metrics.height;
5129 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5130 pFT_Vector_Transform(&vec, &transMat);
5131 if(xc == 0 && yc == 0) {
5132 left = right = vec.x;
5133 top = bottom = vec.y;
5134 } else {
5135 if(vec.x < left) left = vec.x;
5136 else if(vec.x > right) right = vec.x;
5137 if(vec.y < bottom) bottom = vec.y;
5138 else if(vec.y > top) top = vec.y;
5142 left = left & -64;
5143 right = (right + 63) & -64;
5144 bottom = bottom & -64;
5145 top = (top + 63) & -64;
5147 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5148 vec.x = ft_face->glyph->metrics.horiAdvance;
5149 vec.y = 0;
5150 pFT_Vector_Transform(&vec, &transMat);
5151 lpgm->gmCellIncX = (vec.x+63) >> 6;
5152 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5154 vec.x = ft_face->glyph->metrics.horiAdvance;
5155 vec.y = 0;
5156 pFT_Vector_Transform(&vec, &transMatUnrotated);
5157 adv = (vec.x+63) >> 6;
5160 lsb = left >> 6;
5161 bbx = (right - left) >> 6;
5162 lpgm->gmBlackBoxX = (right - left) >> 6;
5163 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5164 lpgm->gmptGlyphOrigin.x = left >> 6;
5165 lpgm->gmptGlyphOrigin.y = top >> 6;
5167 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5168 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5169 lpgm->gmCellIncX, lpgm->gmCellIncY);
5171 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5172 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5174 FONT_GM(font,original_index)->gm = *lpgm;
5175 FONT_GM(font,original_index)->adv = adv;
5176 FONT_GM(font,original_index)->lsb = lsb;
5177 FONT_GM(font,original_index)->bbx = bbx;
5178 FONT_GM(font,original_index)->init = TRUE;
5181 if(format == GGO_METRICS)
5183 LeaveCriticalSection( &freetype_cs );
5184 return 1; /* FIXME */
5187 if(ft_face->glyph->format != ft_glyph_format_outline &&
5188 (format == GGO_NATIVE || format == GGO_BEZIER ||
5189 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5190 format == GGO_GRAY8_BITMAP))
5192 TRACE("loaded a bitmap\n");
5193 LeaveCriticalSection( &freetype_cs );
5194 return GDI_ERROR;
5197 switch(format) {
5198 case GGO_BITMAP:
5199 width = lpgm->gmBlackBoxX;
5200 height = lpgm->gmBlackBoxY;
5201 pitch = ((width + 31) >> 5) << 2;
5202 needed = pitch * height;
5204 if(!buf || !buflen) break;
5206 switch(ft_face->glyph->format) {
5207 case ft_glyph_format_bitmap:
5209 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5210 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5211 INT h = ft_face->glyph->bitmap.rows;
5212 while(h--) {
5213 memcpy(dst, src, w);
5214 src += ft_face->glyph->bitmap.pitch;
5215 dst += pitch;
5217 break;
5220 case ft_glyph_format_outline:
5221 ft_bitmap.width = width;
5222 ft_bitmap.rows = height;
5223 ft_bitmap.pitch = pitch;
5224 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5225 ft_bitmap.buffer = buf;
5227 if(needsTransform)
5228 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5230 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5232 /* Note: FreeType will only set 'black' bits for us. */
5233 memset(buf, 0, needed);
5234 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5235 break;
5237 default:
5238 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5239 LeaveCriticalSection( &freetype_cs );
5240 return GDI_ERROR;
5242 break;
5244 case GGO_GRAY2_BITMAP:
5245 case GGO_GRAY4_BITMAP:
5246 case GGO_GRAY8_BITMAP:
5247 case WINE_GGO_GRAY16_BITMAP:
5249 unsigned int mult, row, col;
5250 BYTE *start, *ptr;
5252 width = lpgm->gmBlackBoxX;
5253 height = lpgm->gmBlackBoxY;
5254 pitch = (width + 3) / 4 * 4;
5255 needed = pitch * height;
5257 if(!buf || !buflen) break;
5259 switch(ft_face->glyph->format) {
5260 case ft_glyph_format_bitmap:
5262 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5263 INT h = ft_face->glyph->bitmap.rows;
5264 INT x;
5265 memset( buf, 0, needed );
5266 while(h--) {
5267 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5268 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5269 src += ft_face->glyph->bitmap.pitch;
5270 dst += pitch;
5272 LeaveCriticalSection( &freetype_cs );
5273 return needed;
5275 case ft_glyph_format_outline:
5277 ft_bitmap.width = width;
5278 ft_bitmap.rows = height;
5279 ft_bitmap.pitch = pitch;
5280 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5281 ft_bitmap.buffer = buf;
5283 if(needsTransform)
5284 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5286 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5288 memset(ft_bitmap.buffer, 0, buflen);
5290 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5292 if(format == GGO_GRAY2_BITMAP)
5293 mult = 4;
5294 else if(format == GGO_GRAY4_BITMAP)
5295 mult = 16;
5296 else if(format == GGO_GRAY8_BITMAP)
5297 mult = 64;
5298 else /* format == WINE_GGO_GRAY16_BITMAP */
5300 LeaveCriticalSection( &freetype_cs );
5301 return needed;
5303 break;
5305 default:
5306 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5307 LeaveCriticalSection( &freetype_cs );
5308 return GDI_ERROR;
5311 start = buf;
5312 for(row = 0; row < height; row++) {
5313 ptr = start;
5314 for(col = 0; col < width; col++, ptr++) {
5315 *ptr = (((int)*ptr) * mult + 128) / 256;
5317 start += pitch;
5319 break;
5322 case WINE_GGO_HRGB_BITMAP:
5323 case WINE_GGO_HBGR_BITMAP:
5324 case WINE_GGO_VRGB_BITMAP:
5325 case WINE_GGO_VBGR_BITMAP:
5326 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5328 switch (ft_face->glyph->format)
5330 case FT_GLYPH_FORMAT_BITMAP:
5332 BYTE *src, *dst;
5333 INT src_pitch, x;
5335 width = lpgm->gmBlackBoxX;
5336 height = lpgm->gmBlackBoxY;
5337 pitch = width * 4;
5338 needed = pitch * height;
5340 if (!buf || !buflen) break;
5342 memset(buf, 0, buflen);
5343 dst = buf;
5344 src = ft_face->glyph->bitmap.buffer;
5345 src_pitch = ft_face->glyph->bitmap.pitch;
5347 height = min( height, ft_face->glyph->bitmap.rows );
5348 while ( height-- )
5350 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5352 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5353 ((unsigned int *)dst)[x] = ~0u;
5355 src += src_pitch;
5356 dst += pitch;
5359 break;
5362 case FT_GLYPH_FORMAT_OUTLINE:
5364 unsigned int *dst;
5365 BYTE *src;
5366 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5367 INT x_shift, y_shift;
5368 BOOL rgb;
5369 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5370 FT_Render_Mode render_mode =
5371 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5372 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5374 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5376 if ( render_mode == FT_RENDER_MODE_LCD)
5378 lpgm->gmBlackBoxX += 2;
5379 lpgm->gmptGlyphOrigin.x -= 1;
5381 else
5383 lpgm->gmBlackBoxY += 2;
5384 lpgm->gmptGlyphOrigin.y += 1;
5388 width = lpgm->gmBlackBoxX;
5389 height = lpgm->gmBlackBoxY;
5390 pitch = width * 4;
5391 needed = pitch * height;
5393 if (!buf || !buflen) break;
5395 memset(buf, 0, buflen);
5396 dst = buf;
5397 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5399 if ( needsTransform )
5400 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5402 if ( pFT_Library_SetLcdFilter )
5403 pFT_Library_SetLcdFilter( library, lcdfilter );
5404 pFT_Render_Glyph (ft_face->glyph, render_mode);
5406 src = ft_face->glyph->bitmap.buffer;
5407 src_pitch = ft_face->glyph->bitmap.pitch;
5408 src_width = ft_face->glyph->bitmap.width;
5409 src_height = ft_face->glyph->bitmap.rows;
5411 if ( render_mode == FT_RENDER_MODE_LCD)
5413 rgb_interval = 1;
5414 hmul = 3;
5415 vmul = 1;
5417 else
5419 rgb_interval = src_pitch;
5420 hmul = 1;
5421 vmul = 3;
5424 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5425 if ( x_shift < 0 ) x_shift = 0;
5426 if ( x_shift + (src_width / hmul) > width )
5427 x_shift = width - (src_width / hmul);
5429 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5430 if ( y_shift < 0 ) y_shift = 0;
5431 if ( y_shift + (src_height / vmul) > height )
5432 y_shift = height - (src_height / vmul);
5434 dst += x_shift + y_shift * ( pitch / 4 );
5435 while ( src_height )
5437 for ( x = 0; x < src_width / hmul; x++ )
5439 if ( rgb )
5441 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5442 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5443 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5444 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5446 else
5448 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5449 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5450 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5451 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5454 src += src_pitch * vmul;
5455 dst += pitch / 4;
5456 src_height -= vmul;
5459 break;
5462 default:
5463 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5464 LeaveCriticalSection ( &freetype_cs );
5465 return GDI_ERROR;
5468 break;
5470 #else
5471 LeaveCriticalSection( &freetype_cs );
5472 return GDI_ERROR;
5473 #endif
5475 case GGO_NATIVE:
5477 int contour, point = 0, first_pt;
5478 FT_Outline *outline = &ft_face->glyph->outline;
5479 TTPOLYGONHEADER *pph;
5480 TTPOLYCURVE *ppc;
5481 DWORD pph_start, cpfx, type;
5483 if(buflen == 0) buf = NULL;
5485 if (needsTransform && buf) {
5486 pFT_Outline_Transform(outline, &transMat);
5489 for(contour = 0; contour < outline->n_contours; contour++) {
5490 pph_start = needed;
5491 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5492 first_pt = point;
5493 if(buf) {
5494 pph->dwType = TT_POLYGON_TYPE;
5495 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5497 needed += sizeof(*pph);
5498 point++;
5499 while(point <= outline->contours[contour]) {
5500 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5501 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5502 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5503 cpfx = 0;
5504 do {
5505 if(buf)
5506 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5507 cpfx++;
5508 point++;
5509 } while(point <= outline->contours[contour] &&
5510 (outline->tags[point] & FT_Curve_Tag_On) ==
5511 (outline->tags[point-1] & FT_Curve_Tag_On));
5512 /* At the end of a contour Windows adds the start point, but
5513 only for Beziers */
5514 if(point > outline->contours[contour] &&
5515 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5516 if(buf)
5517 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5518 cpfx++;
5519 } else if(point <= outline->contours[contour] &&
5520 outline->tags[point] & FT_Curve_Tag_On) {
5521 /* add closing pt for bezier */
5522 if(buf)
5523 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5524 cpfx++;
5525 point++;
5527 if(buf) {
5528 ppc->wType = type;
5529 ppc->cpfx = cpfx;
5531 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5533 if(buf)
5534 pph->cb = needed - pph_start;
5536 break;
5538 case GGO_BEZIER:
5540 /* Convert the quadratic Beziers to cubic Beziers.
5541 The parametric eqn for a cubic Bezier is, from PLRM:
5542 r(t) = at^3 + bt^2 + ct + r0
5543 with the control points:
5544 r1 = r0 + c/3
5545 r2 = r1 + (c + b)/3
5546 r3 = r0 + c + b + a
5548 A quadratic Bezier has the form:
5549 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5551 So equating powers of t leads to:
5552 r1 = 2/3 p1 + 1/3 p0
5553 r2 = 2/3 p1 + 1/3 p2
5554 and of course r0 = p0, r3 = p2
5557 int contour, point = 0, first_pt;
5558 FT_Outline *outline = &ft_face->glyph->outline;
5559 TTPOLYGONHEADER *pph;
5560 TTPOLYCURVE *ppc;
5561 DWORD pph_start, cpfx, type;
5562 FT_Vector cubic_control[4];
5563 if(buflen == 0) buf = NULL;
5565 if (needsTransform && buf) {
5566 pFT_Outline_Transform(outline, &transMat);
5569 for(contour = 0; contour < outline->n_contours; contour++) {
5570 pph_start = needed;
5571 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5572 first_pt = point;
5573 if(buf) {
5574 pph->dwType = TT_POLYGON_TYPE;
5575 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5577 needed += sizeof(*pph);
5578 point++;
5579 while(point <= outline->contours[contour]) {
5580 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5581 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5582 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5583 cpfx = 0;
5584 do {
5585 if(type == TT_PRIM_LINE) {
5586 if(buf)
5587 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5588 cpfx++;
5589 point++;
5590 } else {
5591 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5592 so cpfx = 3n */
5594 /* FIXME: Possible optimization in endpoint calculation
5595 if there are two consecutive curves */
5596 cubic_control[0] = outline->points[point-1];
5597 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5598 cubic_control[0].x += outline->points[point].x + 1;
5599 cubic_control[0].y += outline->points[point].y + 1;
5600 cubic_control[0].x >>= 1;
5601 cubic_control[0].y >>= 1;
5603 if(point+1 > outline->contours[contour])
5604 cubic_control[3] = outline->points[first_pt];
5605 else {
5606 cubic_control[3] = outline->points[point+1];
5607 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5608 cubic_control[3].x += outline->points[point].x + 1;
5609 cubic_control[3].y += outline->points[point].y + 1;
5610 cubic_control[3].x >>= 1;
5611 cubic_control[3].y >>= 1;
5614 /* r1 = 1/3 p0 + 2/3 p1
5615 r2 = 1/3 p2 + 2/3 p1 */
5616 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5617 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5618 cubic_control[2] = cubic_control[1];
5619 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5620 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5621 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5622 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5623 if(buf) {
5624 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5625 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5626 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5628 cpfx += 3;
5629 point++;
5631 } while(point <= outline->contours[contour] &&
5632 (outline->tags[point] & FT_Curve_Tag_On) ==
5633 (outline->tags[point-1] & FT_Curve_Tag_On));
5634 /* At the end of a contour Windows adds the start point,
5635 but only for Beziers and we've already done that.
5637 if(point <= outline->contours[contour] &&
5638 outline->tags[point] & FT_Curve_Tag_On) {
5639 /* This is the closing pt of a bezier, but we've already
5640 added it, so just inc point and carry on */
5641 point++;
5643 if(buf) {
5644 ppc->wType = type;
5645 ppc->cpfx = cpfx;
5647 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5649 if(buf)
5650 pph->cb = needed - pph_start;
5652 break;
5655 default:
5656 FIXME("Unsupported format %d\n", format);
5657 LeaveCriticalSection( &freetype_cs );
5658 return GDI_ERROR;
5660 LeaveCriticalSection( &freetype_cs );
5661 return needed;
5664 static BOOL get_bitmap_text_metrics(GdiFont *font)
5666 FT_Face ft_face = font->ft_face;
5667 #ifdef HAVE_FREETYPE_FTWINFNT_H
5668 FT_WinFNT_HeaderRec winfnt_header;
5669 #endif
5670 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5671 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5672 font->potm->otmSize = size;
5674 #define TM font->potm->otmTextMetrics
5675 #ifdef HAVE_FREETYPE_FTWINFNT_H
5676 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5678 TM.tmHeight = winfnt_header.pixel_height;
5679 TM.tmAscent = winfnt_header.ascent;
5680 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5681 TM.tmInternalLeading = winfnt_header.internal_leading;
5682 TM.tmExternalLeading = winfnt_header.external_leading;
5683 TM.tmAveCharWidth = winfnt_header.avg_width;
5684 TM.tmMaxCharWidth = winfnt_header.max_width;
5685 TM.tmWeight = winfnt_header.weight;
5686 TM.tmOverhang = 0;
5687 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5688 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5689 TM.tmFirstChar = winfnt_header.first_char;
5690 TM.tmLastChar = winfnt_header.last_char;
5691 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5692 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5693 TM.tmItalic = winfnt_header.italic;
5694 TM.tmUnderlined = font->underline;
5695 TM.tmStruckOut = font->strikeout;
5696 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5697 TM.tmCharSet = winfnt_header.charset;
5699 else
5700 #endif
5702 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5703 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5704 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5705 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5706 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5707 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5708 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5709 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5710 TM.tmOverhang = 0;
5711 TM.tmDigitizedAspectX = 96; /* FIXME */
5712 TM.tmDigitizedAspectY = 96; /* FIXME */
5713 TM.tmFirstChar = 1;
5714 TM.tmLastChar = 255;
5715 TM.tmDefaultChar = 32;
5716 TM.tmBreakChar = 32;
5717 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5718 TM.tmUnderlined = font->underline;
5719 TM.tmStruckOut = font->strikeout;
5720 /* NB inverted meaning of TMPF_FIXED_PITCH */
5721 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5722 TM.tmCharSet = font->charset;
5724 #undef TM
5726 return TRUE;
5730 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5732 double scale_x, scale_y;
5734 if (font->aveWidth)
5736 scale_x = (double)font->aveWidth;
5737 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5739 else
5740 scale_x = font->scale_y;
5742 scale_x *= fabs(font->font_desc.matrix.eM11);
5743 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5745 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5746 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5748 SCALE_Y(ptm->tmHeight);
5749 SCALE_Y(ptm->tmAscent);
5750 SCALE_Y(ptm->tmDescent);
5751 SCALE_Y(ptm->tmInternalLeading);
5752 SCALE_Y(ptm->tmExternalLeading);
5753 SCALE_Y(ptm->tmOverhang);
5755 SCALE_X(ptm->tmAveCharWidth);
5756 SCALE_X(ptm->tmMaxCharWidth);
5758 #undef SCALE_X
5759 #undef SCALE_Y
5762 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5764 double scale_x, scale_y;
5766 if (font->aveWidth)
5768 scale_x = (double)font->aveWidth;
5769 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5771 else
5772 scale_x = font->scale_y;
5774 scale_x *= fabs(font->font_desc.matrix.eM11);
5775 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5777 scale_font_metrics(font, &potm->otmTextMetrics);
5779 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5780 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5782 SCALE_Y(potm->otmAscent);
5783 SCALE_Y(potm->otmDescent);
5784 SCALE_Y(potm->otmLineGap);
5785 SCALE_Y(potm->otmsCapEmHeight);
5786 SCALE_Y(potm->otmsXHeight);
5787 SCALE_Y(potm->otmrcFontBox.top);
5788 SCALE_Y(potm->otmrcFontBox.bottom);
5789 SCALE_X(potm->otmrcFontBox.left);
5790 SCALE_X(potm->otmrcFontBox.right);
5791 SCALE_Y(potm->otmMacAscent);
5792 SCALE_Y(potm->otmMacDescent);
5793 SCALE_Y(potm->otmMacLineGap);
5794 SCALE_X(potm->otmptSubscriptSize.x);
5795 SCALE_Y(potm->otmptSubscriptSize.y);
5796 SCALE_X(potm->otmptSubscriptOffset.x);
5797 SCALE_Y(potm->otmptSubscriptOffset.y);
5798 SCALE_X(potm->otmptSuperscriptSize.x);
5799 SCALE_Y(potm->otmptSuperscriptSize.y);
5800 SCALE_X(potm->otmptSuperscriptOffset.x);
5801 SCALE_Y(potm->otmptSuperscriptOffset.y);
5802 SCALE_Y(potm->otmsStrikeoutSize);
5803 SCALE_Y(potm->otmsStrikeoutPosition);
5804 SCALE_Y(potm->otmsUnderscoreSize);
5805 SCALE_Y(potm->otmsUnderscorePosition);
5807 #undef SCALE_X
5808 #undef SCALE_Y
5811 /*************************************************************
5812 * WineEngGetTextMetrics
5815 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5817 GDI_CheckNotLock();
5818 EnterCriticalSection( &freetype_cs );
5819 if(!font->potm) {
5820 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5821 if(!get_bitmap_text_metrics(font))
5823 LeaveCriticalSection( &freetype_cs );
5824 return FALSE;
5827 /* Make sure that the font has sane width/height ratio */
5828 if (font->aveWidth)
5830 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5832 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5833 font->aveWidth = 0;
5838 *ptm = font->potm->otmTextMetrics;
5839 scale_font_metrics(font, ptm);
5840 LeaveCriticalSection( &freetype_cs );
5841 return TRUE;
5844 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5846 int i;
5848 for(i = 0; i < ft_face->num_charmaps; i++)
5850 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5851 return TRUE;
5853 return FALSE;
5856 /*************************************************************
5857 * WineEngGetOutlineTextMetrics
5860 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5861 OUTLINETEXTMETRICW *potm)
5863 FT_Face ft_face = font->ft_face;
5864 UINT needed, lenfam, lensty, ret;
5865 TT_OS2 *pOS2;
5866 TT_HoriHeader *pHori;
5867 TT_Postscript *pPost;
5868 FT_Fixed x_scale, y_scale;
5869 WCHAR *family_nameW, *style_nameW;
5870 static const WCHAR spaceW[] = {' ', '\0'};
5871 char *cp;
5872 INT ascent, descent;
5874 TRACE("font=%p\n", font);
5876 if(!FT_IS_SCALABLE(ft_face))
5877 return 0;
5879 GDI_CheckNotLock();
5880 EnterCriticalSection( &freetype_cs );
5882 if(font->potm) {
5883 if(cbSize >= font->potm->otmSize)
5885 memcpy(potm, font->potm, font->potm->otmSize);
5886 scale_outline_font_metrics(font, potm);
5888 LeaveCriticalSection( &freetype_cs );
5889 return font->potm->otmSize;
5893 needed = sizeof(*potm);
5895 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5896 family_nameW = strdupW(font->name);
5898 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5899 * sizeof(WCHAR);
5900 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5901 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5902 style_nameW, lensty/sizeof(WCHAR));
5904 /* These names should be read from the TT name table */
5906 /* length of otmpFamilyName */
5907 needed += lenfam;
5909 /* length of otmpFaceName */
5910 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5911 needed += lenfam; /* just the family name */
5912 } else {
5913 needed += lenfam + lensty; /* family + " " + style */
5916 /* length of otmpStyleName */
5917 needed += lensty;
5919 /* length of otmpFullName */
5920 needed += lenfam + lensty;
5923 x_scale = ft_face->size->metrics.x_scale;
5924 y_scale = ft_face->size->metrics.y_scale;
5926 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5927 if(!pOS2) {
5928 FIXME("Can't find OS/2 table - not TT font?\n");
5929 ret = 0;
5930 goto end;
5933 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5934 if(!pHori) {
5935 FIXME("Can't find HHEA table - not TT font?\n");
5936 ret = 0;
5937 goto end;
5940 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5942 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",
5943 pOS2->usWinAscent, pOS2->usWinDescent,
5944 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5945 ft_face->ascender, ft_face->descender, ft_face->height,
5946 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5947 ft_face->bbox.yMax, ft_face->bbox.yMin);
5949 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5950 font->potm->otmSize = needed;
5952 #define TM font->potm->otmTextMetrics
5954 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5955 ascent = pHori->Ascender;
5956 descent = -pHori->Descender;
5957 } else {
5958 ascent = pOS2->usWinAscent;
5959 descent = pOS2->usWinDescent;
5962 if(font->yMax) {
5963 TM.tmAscent = font->yMax;
5964 TM.tmDescent = -font->yMin;
5965 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5966 } else {
5967 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5968 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5969 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5970 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5973 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5975 /* MSDN says:
5976 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5978 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5979 ((ascent + descent) -
5980 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5982 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5983 if (TM.tmAveCharWidth == 0) {
5984 TM.tmAveCharWidth = 1;
5986 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5987 TM.tmWeight = FW_REGULAR;
5988 if (font->fake_bold)
5989 TM.tmWeight = FW_BOLD;
5990 else
5992 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5994 if (pOS2->usWeightClass > FW_MEDIUM)
5995 TM.tmWeight = pOS2->usWeightClass;
5997 else if (pOS2->usWeightClass <= FW_MEDIUM)
5998 TM.tmWeight = pOS2->usWeightClass;
6000 TM.tmOverhang = 0;
6001 TM.tmDigitizedAspectX = 300;
6002 TM.tmDigitizedAspectY = 300;
6003 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6004 * symbol range to 0 - f0ff
6007 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6009 TM.tmFirstChar = 0;
6010 switch(GetACP())
6012 case 1257: /* Baltic */
6013 TM.tmLastChar = 0xf8fd;
6014 break;
6015 default:
6016 TM.tmLastChar = 0xf0ff;
6018 TM.tmBreakChar = 0x20;
6019 TM.tmDefaultChar = 0x1f;
6021 else
6023 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6024 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6026 if(pOS2->usFirstCharIndex <= 1)
6027 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6028 else if (pOS2->usFirstCharIndex > 0xff)
6029 TM.tmBreakChar = 0x20;
6030 else
6031 TM.tmBreakChar = pOS2->usFirstCharIndex;
6032 TM.tmDefaultChar = TM.tmBreakChar - 1;
6034 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6035 TM.tmUnderlined = font->underline;
6036 TM.tmStruckOut = font->strikeout;
6038 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6039 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6040 (pOS2->version == 0xFFFFU ||
6041 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6042 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6043 else
6044 TM.tmPitchAndFamily = 0;
6046 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6048 case PAN_FAMILY_SCRIPT:
6049 TM.tmPitchAndFamily |= FF_SCRIPT;
6050 break;
6052 case PAN_FAMILY_DECORATIVE:
6053 TM.tmPitchAndFamily |= FF_DECORATIVE;
6054 break;
6056 case PAN_ANY:
6057 case PAN_NO_FIT:
6058 case PAN_FAMILY_TEXT_DISPLAY:
6059 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6060 /* which is clearly not what the panose spec says. */
6061 default:
6062 if(TM.tmPitchAndFamily == 0 || /* fixed */
6063 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6064 TM.tmPitchAndFamily = FF_MODERN;
6065 else
6067 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6069 case PAN_ANY:
6070 case PAN_NO_FIT:
6071 default:
6072 TM.tmPitchAndFamily |= FF_DONTCARE;
6073 break;
6075 case PAN_SERIF_COVE:
6076 case PAN_SERIF_OBTUSE_COVE:
6077 case PAN_SERIF_SQUARE_COVE:
6078 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6079 case PAN_SERIF_SQUARE:
6080 case PAN_SERIF_THIN:
6081 case PAN_SERIF_BONE:
6082 case PAN_SERIF_EXAGGERATED:
6083 case PAN_SERIF_TRIANGLE:
6084 TM.tmPitchAndFamily |= FF_ROMAN;
6085 break;
6087 case PAN_SERIF_NORMAL_SANS:
6088 case PAN_SERIF_OBTUSE_SANS:
6089 case PAN_SERIF_PERP_SANS:
6090 case PAN_SERIF_FLARED:
6091 case PAN_SERIF_ROUNDED:
6092 TM.tmPitchAndFamily |= FF_SWISS;
6093 break;
6096 break;
6099 if(FT_IS_SCALABLE(ft_face))
6100 TM.tmPitchAndFamily |= TMPF_VECTOR;
6102 if(FT_IS_SFNT(ft_face))
6104 if (font->ntmFlags & NTM_PS_OPENTYPE)
6105 TM.tmPitchAndFamily |= TMPF_DEVICE;
6106 else
6107 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6110 TM.tmCharSet = font->charset;
6112 font->potm->otmFiller = 0;
6113 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6114 font->potm->otmfsSelection = pOS2->fsSelection;
6115 font->potm->otmfsType = pOS2->fsType;
6116 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6117 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6118 font->potm->otmItalicAngle = 0; /* POST table */
6119 font->potm->otmEMSquare = ft_face->units_per_EM;
6120 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6121 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6122 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6123 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6124 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6125 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6126 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6127 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6128 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6129 font->potm->otmMacAscent = TM.tmAscent;
6130 font->potm->otmMacDescent = -TM.tmDescent;
6131 font->potm->otmMacLineGap = font->potm->otmLineGap;
6132 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6133 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6134 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6135 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6136 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6137 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6138 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6139 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6140 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6141 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6142 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6143 if(!pPost) {
6144 font->potm->otmsUnderscoreSize = 0;
6145 font->potm->otmsUnderscorePosition = 0;
6146 } else {
6147 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6148 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6150 #undef TM
6152 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6153 cp = (char*)font->potm + sizeof(*font->potm);
6154 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6155 strcpyW((WCHAR*)cp, family_nameW);
6156 cp += lenfam;
6157 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6158 strcpyW((WCHAR*)cp, style_nameW);
6159 cp += lensty;
6160 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6161 strcpyW((WCHAR*)cp, family_nameW);
6162 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6163 strcatW((WCHAR*)cp, spaceW);
6164 strcatW((WCHAR*)cp, style_nameW);
6165 cp += lenfam + lensty;
6166 } else
6167 cp += lenfam;
6168 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6169 strcpyW((WCHAR*)cp, family_nameW);
6170 strcatW((WCHAR*)cp, spaceW);
6171 strcatW((WCHAR*)cp, style_nameW);
6172 ret = needed;
6174 if(potm && needed <= cbSize)
6176 memcpy(potm, font->potm, font->potm->otmSize);
6177 scale_outline_font_metrics(font, potm);
6180 end:
6181 HeapFree(GetProcessHeap(), 0, style_nameW);
6182 HeapFree(GetProcessHeap(), 0, family_nameW);
6184 LeaveCriticalSection( &freetype_cs );
6185 return ret;
6188 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6190 HFONTLIST *hfontlist;
6191 child->font = alloc_font();
6192 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6193 if(!child->font->ft_face)
6195 free_font(child->font);
6196 child->font = NULL;
6197 return FALSE;
6200 child->font->font_desc = font->font_desc;
6201 child->font->ntmFlags = child->face->ntmFlags;
6202 child->font->orientation = font->orientation;
6203 child->font->scale_y = font->scale_y;
6204 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6205 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6206 child->font->name = strdupW(child->face->family->FamilyName);
6207 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6208 child->font->base_font = font;
6209 list_add_head(&child_font_list, &child->font->entry);
6210 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6211 return TRUE;
6214 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6216 FT_UInt g;
6217 CHILD_FONT *child_font;
6219 if(font->base_font)
6220 font = font->base_font;
6222 *linked_font = font;
6224 if((*glyph = get_glyph_index(font, c)))
6225 return TRUE;
6227 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6229 if(!child_font->font)
6230 if(!load_child_font(font, child_font))
6231 continue;
6233 if(!child_font->font->ft_face)
6234 continue;
6235 g = get_glyph_index(child_font->font, c);
6236 if(g)
6238 *glyph = g;
6239 *linked_font = child_font->font;
6240 return TRUE;
6243 return FALSE;
6246 /*************************************************************
6247 * WineEngGetCharWidth
6250 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6251 LPINT buffer)
6253 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6254 UINT c;
6255 GLYPHMETRICS gm;
6256 FT_UInt glyph_index;
6257 GdiFont *linked_font;
6259 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6261 GDI_CheckNotLock();
6262 EnterCriticalSection( &freetype_cs );
6263 for(c = firstChar; c <= lastChar; c++) {
6264 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6265 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6266 &gm, 0, NULL, &identity);
6267 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6269 LeaveCriticalSection( &freetype_cs );
6270 return TRUE;
6273 /*************************************************************
6274 * WineEngGetCharABCWidths
6277 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6278 LPABC buffer)
6280 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6281 UINT c;
6282 GLYPHMETRICS gm;
6283 FT_UInt glyph_index;
6284 GdiFont *linked_font;
6286 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6288 if(!FT_IS_SCALABLE(font->ft_face))
6289 return FALSE;
6291 GDI_CheckNotLock();
6292 EnterCriticalSection( &freetype_cs );
6294 for(c = firstChar; c <= lastChar; c++) {
6295 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6296 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6297 &gm, 0, NULL, &identity);
6298 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6299 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6300 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6301 FONT_GM(linked_font,glyph_index)->bbx;
6303 LeaveCriticalSection( &freetype_cs );
6304 return TRUE;
6307 /*************************************************************
6308 * WineEngGetCharABCWidthsFloat
6311 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6313 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6314 UINT c;
6315 GLYPHMETRICS gm;
6316 FT_UInt glyph_index;
6317 GdiFont *linked_font;
6319 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6321 GDI_CheckNotLock();
6322 EnterCriticalSection( &freetype_cs );
6324 for (c = first; c <= last; c++)
6326 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6327 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6328 &gm, 0, NULL, &identity);
6329 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6330 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6331 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6332 FONT_GM(linked_font, glyph_index)->lsb -
6333 FONT_GM(linked_font, glyph_index)->bbx;
6335 LeaveCriticalSection( &freetype_cs );
6336 return TRUE;
6339 /*************************************************************
6340 * WineEngGetCharABCWidthsI
6343 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6344 LPABC buffer)
6346 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6347 UINT c;
6348 GLYPHMETRICS gm;
6349 FT_UInt glyph_index;
6350 GdiFont *linked_font;
6352 if(!FT_HAS_HORIZONTAL(font->ft_face))
6353 return FALSE;
6355 GDI_CheckNotLock();
6356 EnterCriticalSection( &freetype_cs );
6358 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6359 if (!pgi)
6360 for(c = firstChar; c < firstChar+count; c++) {
6361 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6362 &gm, 0, NULL, &identity);
6363 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6364 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6365 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6366 - FONT_GM(linked_font,c)->bbx;
6368 else
6369 for(c = 0; c < count; c++) {
6370 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6371 &gm, 0, NULL, &identity);
6372 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6373 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6374 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6375 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6378 LeaveCriticalSection( &freetype_cs );
6379 return TRUE;
6382 /*************************************************************
6383 * WineEngGetTextExtentExPoint
6386 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6387 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6389 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6390 INT idx;
6391 INT nfit = 0, ext;
6392 GLYPHMETRICS gm;
6393 TEXTMETRICW tm;
6394 FT_UInt glyph_index;
6395 GdiFont *linked_font;
6397 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6398 max_ext, size);
6400 GDI_CheckNotLock();
6401 EnterCriticalSection( &freetype_cs );
6403 size->cx = 0;
6404 WineEngGetTextMetrics(font, &tm);
6405 size->cy = tm.tmHeight;
6407 for(idx = 0; idx < count; idx++) {
6408 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6409 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6410 &gm, 0, NULL, &identity);
6411 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6412 ext = size->cx;
6413 if (! pnfit || ext <= max_ext) {
6414 ++nfit;
6415 if (dxs)
6416 dxs[idx] = ext;
6420 if (pnfit)
6421 *pnfit = nfit;
6423 LeaveCriticalSection( &freetype_cs );
6424 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6425 return TRUE;
6428 /*************************************************************
6429 * WineEngGetTextExtentExPointI
6432 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6433 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6435 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6436 INT idx;
6437 INT nfit = 0, ext;
6438 GLYPHMETRICS gm;
6439 TEXTMETRICW tm;
6441 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6443 GDI_CheckNotLock();
6444 EnterCriticalSection( &freetype_cs );
6446 size->cx = 0;
6447 WineEngGetTextMetrics(font, &tm);
6448 size->cy = tm.tmHeight;
6450 for(idx = 0; idx < count; idx++) {
6451 WineEngGetGlyphOutline(font, indices[idx],
6452 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6453 &identity);
6454 size->cx += FONT_GM(font,indices[idx])->adv;
6455 ext = size->cx;
6456 if (! pnfit || ext <= max_ext) {
6457 ++nfit;
6458 if (dxs)
6459 dxs[idx] = ext;
6463 if (pnfit)
6464 *pnfit = nfit;
6466 LeaveCriticalSection( &freetype_cs );
6467 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6468 return TRUE;
6471 /*************************************************************
6472 * WineEngGetFontData
6475 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6476 DWORD cbData)
6478 FT_Face ft_face = font->ft_face;
6479 FT_ULong len;
6480 FT_Error err;
6482 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6483 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6484 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6486 if(!FT_IS_SFNT(ft_face))
6487 return GDI_ERROR;
6489 if(!buf)
6490 len = 0;
6491 else
6492 len = cbData;
6494 if(table) { /* MS tags differ in endianness from FT ones */
6495 table = table >> 24 | table << 24 |
6496 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6499 /* make sure value of len is the value freetype says it needs */
6500 if(buf && len)
6502 FT_ULong needed = 0;
6503 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
6504 if( !err && needed < len) len = needed;
6506 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
6508 if(err) {
6509 TRACE("Can't find table %c%c%c%c\n",
6510 /* bytes were reversed */
6511 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6512 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6513 return GDI_ERROR;
6515 return len;
6518 /*************************************************************
6519 * WineEngGetTextFace
6522 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6524 INT n = strlenW(font->name) + 1;
6525 if(str) {
6526 lstrcpynW(str, font->name, count);
6527 return min(count, n);
6528 } else
6529 return n;
6532 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6534 if (fs) *fs = font->fs;
6535 return font->charset;
6538 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6540 GdiFont *font = dc->gdiFont, *linked_font;
6541 struct list *first_hfont;
6542 BOOL ret;
6544 GDI_CheckNotLock();
6545 EnterCriticalSection( &freetype_cs );
6546 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6547 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6548 if(font == linked_font)
6549 *new_hfont = dc->hFont;
6550 else
6552 first_hfont = list_head(&linked_font->hfontlist);
6553 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6555 LeaveCriticalSection( &freetype_cs );
6556 return ret;
6559 /* Retrieve a list of supported Unicode ranges for a given font.
6560 * Can be called with NULL gs to calculate the buffer size. Returns
6561 * the number of ranges found.
6563 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6565 DWORD num_ranges = 0;
6567 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6569 FT_UInt glyph_code;
6570 FT_ULong char_code, char_code_prev;
6572 glyph_code = 0;
6573 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6575 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6576 face->num_glyphs, glyph_code, char_code);
6578 if (!glyph_code) return 0;
6580 if (gs)
6582 gs->ranges[0].wcLow = (USHORT)char_code;
6583 gs->ranges[0].cGlyphs = 0;
6584 gs->cGlyphsSupported = 0;
6587 num_ranges = 1;
6588 while (glyph_code)
6590 if (char_code < char_code_prev)
6592 ERR("expected increasing char code from FT_Get_Next_Char\n");
6593 return 0;
6595 if (char_code - char_code_prev > 1)
6597 num_ranges++;
6598 if (gs)
6600 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6601 gs->ranges[num_ranges - 1].cGlyphs = 1;
6602 gs->cGlyphsSupported++;
6605 else if (gs)
6607 gs->ranges[num_ranges - 1].cGlyphs++;
6608 gs->cGlyphsSupported++;
6610 char_code_prev = char_code;
6611 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6614 else
6615 FIXME("encoding %u not supported\n", face->charmap->encoding);
6617 return num_ranges;
6620 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6622 DWORD size = 0;
6623 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6625 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6626 if (glyphset)
6628 glyphset->cbThis = size;
6629 glyphset->cRanges = num_ranges;
6630 glyphset->flAccel = 0;
6632 return size;
6635 /*************************************************************
6636 * FontIsLinked
6638 BOOL WineEngFontIsLinked(GdiFont *font)
6640 BOOL ret;
6641 GDI_CheckNotLock();
6642 EnterCriticalSection( &freetype_cs );
6643 ret = !list_empty(&font->child_fonts);
6644 LeaveCriticalSection( &freetype_cs );
6645 return ret;
6648 static BOOL is_hinting_enabled(void)
6650 /* Use the >= 2.2.0 function if available */
6651 if(pFT_Get_TrueType_Engine_Type)
6653 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6654 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6656 #ifdef FT_DRIVER_HAS_HINTER
6657 else
6659 FT_Module mod;
6661 /* otherwise if we've been compiled with < 2.2.0 headers
6662 use the internal macro */
6663 mod = pFT_Get_Module(library, "truetype");
6664 if(mod && FT_DRIVER_HAS_HINTER(mod))
6665 return TRUE;
6667 #endif
6669 return FALSE;
6672 static BOOL is_subpixel_rendering_enabled( void )
6674 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6675 return pFT_Library_SetLcdFilter &&
6676 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6677 #else
6678 return FALSE;
6679 #endif
6682 /*************************************************************************
6683 * GetRasterizerCaps (GDI32.@)
6685 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6687 static int hinting = -1;
6688 static int subpixel = -1;
6690 if(hinting == -1)
6692 hinting = is_hinting_enabled();
6693 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6696 if ( subpixel == -1 )
6698 subpixel = is_subpixel_rendering_enabled();
6699 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6702 lprs->nSize = sizeof(RASTERIZER_STATUS);
6703 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6704 if ( subpixel )
6705 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6706 lprs->nLanguageID = 0;
6707 return TRUE;
6710 /*************************************************************
6711 * WineEngRealizationInfo
6713 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6715 FIXME("(%p, %p): stub!\n", font, info);
6717 info->flags = 1;
6718 if(FT_IS_SCALABLE(font->ft_face))
6719 info->flags |= 2;
6721 info->cache_num = font->cache_num;
6722 info->unknown2 = -1;
6723 return TRUE;
6726 /*************************************************************************
6727 * Kerning support for TrueType fonts
6729 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6731 struct TT_kern_table
6733 USHORT version;
6734 USHORT nTables;
6737 struct TT_kern_subtable
6739 USHORT version;
6740 USHORT length;
6741 union
6743 USHORT word;
6744 struct
6746 USHORT horizontal : 1;
6747 USHORT minimum : 1;
6748 USHORT cross_stream: 1;
6749 USHORT override : 1;
6750 USHORT reserved1 : 4;
6751 USHORT format : 8;
6752 } bits;
6753 } coverage;
6756 struct TT_format0_kern_subtable
6758 USHORT nPairs;
6759 USHORT searchRange;
6760 USHORT entrySelector;
6761 USHORT rangeShift;
6764 struct TT_kern_pair
6766 USHORT left;
6767 USHORT right;
6768 short value;
6771 static DWORD parse_format0_kern_subtable(GdiFont *font,
6772 const struct TT_format0_kern_subtable *tt_f0_ks,
6773 const USHORT *glyph_to_char,
6774 KERNINGPAIR *kern_pair, DWORD cPairs)
6776 USHORT i, nPairs;
6777 const struct TT_kern_pair *tt_kern_pair;
6779 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6781 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6783 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6784 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6785 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6787 if (!kern_pair || !cPairs)
6788 return nPairs;
6790 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6792 nPairs = min(nPairs, cPairs);
6794 for (i = 0; i < nPairs; i++)
6796 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6797 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6798 /* this algorithm appears to better match what Windows does */
6799 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6800 if (kern_pair->iKernAmount < 0)
6802 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6803 kern_pair->iKernAmount -= font->ppem;
6805 else if (kern_pair->iKernAmount > 0)
6807 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6808 kern_pair->iKernAmount += font->ppem;
6810 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6812 TRACE("left %u right %u value %d\n",
6813 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6815 kern_pair++;
6817 TRACE("copied %u entries\n", nPairs);
6818 return nPairs;
6821 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6823 DWORD length;
6824 void *buf;
6825 const struct TT_kern_table *tt_kern_table;
6826 const struct TT_kern_subtable *tt_kern_subtable;
6827 USHORT i, nTables;
6828 USHORT *glyph_to_char;
6830 GDI_CheckNotLock();
6831 EnterCriticalSection( &freetype_cs );
6832 if (font->total_kern_pairs != (DWORD)-1)
6834 if (cPairs && kern_pair)
6836 cPairs = min(cPairs, font->total_kern_pairs);
6837 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6838 LeaveCriticalSection( &freetype_cs );
6839 return cPairs;
6841 LeaveCriticalSection( &freetype_cs );
6842 return font->total_kern_pairs;
6845 font->total_kern_pairs = 0;
6847 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6849 if (length == GDI_ERROR)
6851 TRACE("no kerning data in the font\n");
6852 LeaveCriticalSection( &freetype_cs );
6853 return 0;
6856 buf = HeapAlloc(GetProcessHeap(), 0, length);
6857 if (!buf)
6859 WARN("Out of memory\n");
6860 LeaveCriticalSection( &freetype_cs );
6861 return 0;
6864 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6866 /* build a glyph index to char code map */
6867 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6868 if (!glyph_to_char)
6870 WARN("Out of memory allocating a glyph index to char code map\n");
6871 HeapFree(GetProcessHeap(), 0, buf);
6872 LeaveCriticalSection( &freetype_cs );
6873 return 0;
6876 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6878 FT_UInt glyph_code;
6879 FT_ULong char_code;
6881 glyph_code = 0;
6882 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6884 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6885 font->ft_face->num_glyphs, glyph_code, char_code);
6887 while (glyph_code)
6889 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6891 /* FIXME: This doesn't match what Windows does: it does some fancy
6892 * things with duplicate glyph index to char code mappings, while
6893 * we just avoid overriding existing entries.
6895 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6896 glyph_to_char[glyph_code] = (USHORT)char_code;
6898 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6901 else
6903 ULONG n;
6905 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6906 for (n = 0; n <= 65535; n++)
6907 glyph_to_char[n] = (USHORT)n;
6910 tt_kern_table = buf;
6911 nTables = GET_BE_WORD(tt_kern_table->nTables);
6912 TRACE("version %u, nTables %u\n",
6913 GET_BE_WORD(tt_kern_table->version), nTables);
6915 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6917 for (i = 0; i < nTables; i++)
6919 struct TT_kern_subtable tt_kern_subtable_copy;
6921 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6922 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6923 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6925 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6926 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6927 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6929 /* According to the TrueType specification this is the only format
6930 * that will be properly interpreted by Windows and OS/2
6932 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6934 DWORD new_chunk, old_total = font->total_kern_pairs;
6936 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6937 glyph_to_char, NULL, 0);
6938 font->total_kern_pairs += new_chunk;
6940 if (!font->kern_pairs)
6941 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6942 font->total_kern_pairs * sizeof(*font->kern_pairs));
6943 else
6944 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6945 font->total_kern_pairs * sizeof(*font->kern_pairs));
6947 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6948 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6950 else
6951 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6953 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6956 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6957 HeapFree(GetProcessHeap(), 0, buf);
6959 if (cPairs && kern_pair)
6961 cPairs = min(cPairs, font->total_kern_pairs);
6962 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6963 LeaveCriticalSection( &freetype_cs );
6964 return cPairs;
6966 LeaveCriticalSection( &freetype_cs );
6967 return font->total_kern_pairs;
6970 #else /* HAVE_FREETYPE */
6972 /*************************************************************************/
6974 BOOL WineEngInit(void)
6976 return FALSE;
6978 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6980 return NULL;
6982 BOOL WineEngDestroyFontInstance(HFONT hfont)
6984 return FALSE;
6987 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6989 return 1;
6992 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6993 LPWORD pgi, DWORD flags)
6995 return GDI_ERROR;
6998 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6999 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
7000 const MAT2* lpmat)
7002 ERR("called but we don't have FreeType\n");
7003 return GDI_ERROR;
7006 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
7008 ERR("called but we don't have FreeType\n");
7009 return FALSE;
7012 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
7013 OUTLINETEXTMETRICW *potm)
7015 ERR("called but we don't have FreeType\n");
7016 return 0;
7019 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
7020 LPINT buffer)
7022 ERR("called but we don't have FreeType\n");
7023 return FALSE;
7026 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
7027 LPABC buffer)
7029 ERR("called but we don't have FreeType\n");
7030 return FALSE;
7033 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
7035 ERR("called but we don't have FreeType\n");
7036 return FALSE;
7039 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
7040 LPABC buffer)
7042 ERR("called but we don't have FreeType\n");
7043 return FALSE;
7046 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
7047 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7049 ERR("called but we don't have FreeType\n");
7050 return FALSE;
7053 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
7054 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7056 ERR("called but we don't have FreeType\n");
7057 return FALSE;
7060 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
7061 DWORD cbData)
7063 ERR("called but we don't have FreeType\n");
7064 return GDI_ERROR;
7067 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
7069 ERR("called but we don't have FreeType\n");
7070 return 0;
7073 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7075 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7076 return 1;
7079 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7081 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7082 return TRUE;
7085 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7087 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7088 return NULL;
7091 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
7093 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
7094 return DEFAULT_CHARSET;
7097 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7099 return FALSE;
7102 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
7104 FIXME("(%p, %p): stub\n", font, glyphset);
7105 return 0;
7108 BOOL WineEngFontIsLinked(GdiFont *font)
7110 return FALSE;
7113 /*************************************************************************
7114 * GetRasterizerCaps (GDI32.@)
7116 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7118 lprs->nSize = sizeof(RASTERIZER_STATUS);
7119 lprs->wFlags = 0;
7120 lprs->nLanguageID = 0;
7121 return TRUE;
7124 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
7126 ERR("called but we don't have FreeType\n");
7127 return 0;
7130 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
7132 ERR("called but we don't have FreeType\n");
7133 return FALSE;
7136 #endif /* HAVE_FREETYPE */