quartz: Free two assert calls from having side effects.
[wine/testsucceed.git] / dlls / gdi32 / freetype.c
blob8a687f408230d827b72cfb2aa3f135b1327bdffa
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_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
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_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
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 /*****************************************************************
1401 * load_sfnt_table
1403 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1404 * of FreeType that don't export this function.
1407 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1410 FT_Error err;
1412 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1413 if(pFT_Load_Sfnt_Table)
1415 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1417 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1418 else /* Do it the hard way */
1420 TT_Face tt_face = (TT_Face) ft_face;
1421 SFNT_Interface *sfnt;
1422 if (FT_Version.major==2 && FT_Version.minor==0)
1424 /* 2.0.x */
1425 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1427 else
1429 /* A field was added in the middle of the structure in 2.1.x */
1430 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1432 err = sfnt->load_any(tt_face, table, offset, buf, len);
1434 #else
1435 else
1437 static int msg;
1438 if(!msg)
1440 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1441 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1442 "Please upgrade your freetype library.\n");
1443 msg++;
1445 err = FT_Err_Unimplemented_Feature;
1447 #endif
1448 return err;
1451 static inline int TestStyles(DWORD flags, DWORD styles)
1453 return (flags & styles) == styles;
1456 static int StyleOrdering(Face *face)
1458 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1459 return 3;
1460 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1461 return 2;
1462 if (TestStyles(face->ntmFlags, NTM_BOLD))
1463 return 1;
1464 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1465 return 0;
1467 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1468 debugstr_w(face->family->FamilyName),
1469 debugstr_w(face->StyleName),
1470 face->ntmFlags);
1472 return 9999;
1475 /* Add a style of face to a font family using an ordering of the list such
1476 that regular fonts come before bold and italic, and single styles come
1477 before compound styles. */
1478 static void AddFaceToFamily(Face *face, Family *family)
1480 struct list *entry;
1482 LIST_FOR_EACH( entry, &family->faces )
1484 Face *ent = LIST_ENTRY(entry, Face, entry);
1485 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1487 list_add_before( entry, &face->entry );
1490 #define ADDFONT_EXTERNAL_FONT 0x01
1491 #define ADDFONT_FORCE_BITMAP 0x02
1492 #define ADDFONT_ADD_TO_CACHE 0x04
1494 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1496 FT_Face ft_face;
1497 TT_OS2 *pOS2;
1498 TT_Header *pHeader = NULL;
1499 WCHAR *english_family, *localised_family, *StyleW;
1500 DWORD len;
1501 Family *family;
1502 Face *face;
1503 struct list *family_elem_ptr, *face_elem_ptr;
1504 FT_Error err;
1505 FT_Long face_index = 0, num_faces;
1506 #ifdef HAVE_FREETYPE_FTWINFNT_H
1507 FT_WinFNT_HeaderRec winfnt_header;
1508 #endif
1509 int i, bitmap_num, internal_leading;
1510 FONTSIGNATURE fs;
1512 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1513 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1515 #ifdef HAVE_CARBON_CARBON_H
1516 if(file && !fake_family)
1518 char **mac_list = expand_mac_font(file);
1519 if(mac_list)
1521 BOOL had_one = FALSE;
1522 char **cursor;
1523 for(cursor = mac_list; *cursor; cursor++)
1525 had_one = TRUE;
1526 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1527 HeapFree(GetProcessHeap(), 0, *cursor);
1529 HeapFree(GetProcessHeap(), 0, mac_list);
1530 if(had_one)
1531 return 1;
1534 #endif /* HAVE_CARBON_CARBON_H */
1536 do {
1537 char *family_name = fake_family;
1539 if (file)
1541 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1542 err = pFT_New_Face(library, file, face_index, &ft_face);
1543 } else
1545 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1546 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1549 if(err != 0) {
1550 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1551 return 0;
1554 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*/
1555 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1556 pFT_Done_Face(ft_face);
1557 return 0;
1560 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1561 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1562 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1563 pFT_Done_Face(ft_face);
1564 return 0;
1567 if(FT_IS_SFNT(ft_face))
1569 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1570 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1571 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1573 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1574 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1575 pFT_Done_Face(ft_face);
1576 return 0;
1579 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1580 we don't want to load these. */
1581 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1583 FT_ULong len = 0;
1585 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1587 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1588 pFT_Done_Face(ft_face);
1589 return 0;
1594 if(!ft_face->family_name || !ft_face->style_name) {
1595 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1596 pFT_Done_Face(ft_face);
1597 return 0;
1600 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1602 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1603 pFT_Done_Face(ft_face);
1604 return 0;
1607 if (target_family)
1609 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1610 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1612 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1613 HeapFree(GetProcessHeap(), 0, localised_family);
1614 num_faces = ft_face->num_faces;
1615 pFT_Done_Face(ft_face);
1616 continue;
1618 HeapFree(GetProcessHeap(), 0, localised_family);
1621 if(!family_name)
1622 family_name = ft_face->family_name;
1624 bitmap_num = 0;
1625 do {
1626 My_FT_Bitmap_Size *size = NULL;
1627 FT_ULong tmp_size;
1629 if(!FT_IS_SCALABLE(ft_face))
1630 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1632 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1633 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1634 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1636 localised_family = NULL;
1637 if(!fake_family) {
1638 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1639 if(localised_family && !strcmpiW(localised_family, english_family)) {
1640 HeapFree(GetProcessHeap(), 0, localised_family);
1641 localised_family = NULL;
1645 family = NULL;
1646 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1647 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1648 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1649 break;
1650 family = NULL;
1652 if(!family) {
1653 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1654 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1655 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1656 list_init(&family->faces);
1657 list_add_tail(&font_list, &family->entry);
1659 if(localised_family) {
1660 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1661 subst->from.name = strdupW(english_family);
1662 subst->from.charset = -1;
1663 subst->to.name = strdupW(localised_family);
1664 subst->to.charset = -1;
1665 add_font_subst(&font_subst_list, subst, 0);
1668 HeapFree(GetProcessHeap(), 0, localised_family);
1669 HeapFree(GetProcessHeap(), 0, english_family);
1671 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1672 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1673 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1675 internal_leading = 0;
1676 memset(&fs, 0, sizeof(fs));
1678 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1679 if(pOS2) {
1680 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1681 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1682 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1683 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1684 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1685 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1686 if(pOS2->version == 0) {
1687 FT_UInt dummy;
1689 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1690 fs.fsCsb[0] |= FS_LATIN1;
1691 else
1692 fs.fsCsb[0] |= FS_SYMBOL;
1695 #ifdef HAVE_FREETYPE_FTWINFNT_H
1696 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1697 CHARSETINFO csi;
1698 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1699 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1700 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1701 fs = csi.fs;
1702 internal_leading = winfnt_header.internal_leading;
1704 #endif
1706 face_elem_ptr = list_head(&family->faces);
1707 while(face_elem_ptr) {
1708 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1709 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1710 if(!strcmpiW(face->StyleName, StyleW) &&
1711 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1712 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1713 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1714 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1716 if(fake_family) {
1717 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1718 HeapFree(GetProcessHeap(), 0, StyleW);
1719 pFT_Done_Face(ft_face);
1720 return 1;
1722 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1723 TRACE("Original font is newer so skipping this one\n");
1724 HeapFree(GetProcessHeap(), 0, StyleW);
1725 pFT_Done_Face(ft_face);
1726 return 1;
1727 } else {
1728 TRACE("Replacing original with this one\n");
1729 list_remove(&face->entry);
1730 HeapFree(GetProcessHeap(), 0, face->file);
1731 HeapFree(GetProcessHeap(), 0, face->StyleName);
1732 HeapFree(GetProcessHeap(), 0, face->FullName);
1733 HeapFree(GetProcessHeap(), 0, face);
1734 break;
1738 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1739 face->cached_enum_data = NULL;
1740 face->StyleName = StyleW;
1741 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1742 if (file)
1744 face->file = strdupA(file);
1745 face->font_data_ptr = NULL;
1746 face->font_data_size = 0;
1748 else
1750 face->file = NULL;
1751 face->font_data_ptr = font_data_ptr;
1752 face->font_data_size = font_data_size;
1754 face->face_index = face_index;
1755 face->ntmFlags = 0;
1756 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1757 face->ntmFlags |= NTM_ITALIC;
1758 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1759 face->ntmFlags |= NTM_BOLD;
1760 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1761 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1762 face->family = family;
1763 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1764 face->fs = fs;
1765 memset(&face->fs_links, 0, sizeof(face->fs_links));
1767 if(FT_IS_SCALABLE(ft_face)) {
1768 memset(&face->size, 0, sizeof(face->size));
1769 face->scalable = TRUE;
1770 } else {
1771 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1772 size->height, size->width, size->size >> 6,
1773 size->x_ppem >> 6, size->y_ppem >> 6);
1774 face->size.height = size->height;
1775 face->size.width = size->width;
1776 face->size.size = size->size;
1777 face->size.x_ppem = size->x_ppem;
1778 face->size.y_ppem = size->y_ppem;
1779 face->size.internal_leading = internal_leading;
1780 face->scalable = FALSE;
1783 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1784 tmp_size = 0;
1785 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1787 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1788 face->ntmFlags |= NTM_PS_OPENTYPE;
1791 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1792 face->fs.fsCsb[0], face->fs.fsCsb[1],
1793 face->fs.fsUsb[0], face->fs.fsUsb[1],
1794 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1797 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1798 for(i = 0; i < ft_face->num_charmaps; i++) {
1799 switch(ft_face->charmaps[i]->encoding) {
1800 case FT_ENCODING_UNICODE:
1801 case FT_ENCODING_APPLE_ROMAN:
1802 face->fs.fsCsb[0] |= FS_LATIN1;
1803 break;
1804 case FT_ENCODING_MS_SYMBOL:
1805 face->fs.fsCsb[0] |= FS_SYMBOL;
1806 break;
1807 default:
1808 break;
1813 if(flags & ADDFONT_ADD_TO_CACHE)
1814 add_face_to_cache(face);
1816 AddFaceToFamily(face, family);
1818 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1820 num_faces = ft_face->num_faces;
1821 pFT_Done_Face(ft_face);
1822 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1823 debugstr_w(StyleW));
1824 } while(num_faces > ++face_index);
1825 return num_faces;
1828 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1830 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1833 static void DumpFontList(void)
1835 Family *family;
1836 Face *face;
1837 struct list *family_elem_ptr, *face_elem_ptr;
1839 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1840 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1841 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1842 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1843 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1844 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1845 if(!face->scalable)
1846 TRACE(" %d", face->size.height);
1847 TRACE("\n");
1850 return;
1853 /***********************************************************
1854 * The replacement list is a way to map an entire font
1855 * family onto another family. For example adding
1857 * [HKCU\Software\Wine\Fonts\Replacements]
1858 * "Wingdings"="Winedings"
1860 * would enumerate the Winedings font both as Winedings and
1861 * Wingdings. However if a real Wingdings font is present the
1862 * replacement does not take place.
1865 static void LoadReplaceList(void)
1867 HKEY hkey;
1868 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1869 LPWSTR value;
1870 LPVOID data;
1871 Family *family;
1872 Face *face;
1873 struct list *family_elem_ptr, *face_elem_ptr;
1874 CHAR familyA[400];
1876 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1877 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1879 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1880 &valuelen, &datalen, NULL, NULL);
1882 valuelen++; /* returned value doesn't include room for '\0' */
1883 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1884 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1886 dlen = datalen;
1887 vlen = valuelen;
1888 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1889 &dlen) == ERROR_SUCCESS) {
1890 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1891 /* "NewName"="Oldname" */
1892 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1894 if(!find_family_from_name(value))
1896 /* Find the old family and hence all of the font files
1897 in that family */
1898 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1899 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1900 if(!strcmpiW(family->FamilyName, data)) {
1901 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1902 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1903 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1904 debugstr_w(face->StyleName), familyA);
1905 /* Now add a new entry with the new family name */
1906 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1907 familyA, family->FamilyName,
1908 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1910 break;
1914 /* reset dlen and vlen */
1915 dlen = datalen;
1916 vlen = valuelen;
1918 HeapFree(GetProcessHeap(), 0, data);
1919 HeapFree(GetProcessHeap(), 0, value);
1920 RegCloseKey(hkey);
1924 /*************************************************************
1925 * init_system_links
1927 static BOOL init_system_links(void)
1929 HKEY hkey;
1930 BOOL ret = FALSE;
1931 DWORD type, max_val, max_data, val_len, data_len, index;
1932 WCHAR *value, *data;
1933 WCHAR *entry, *next;
1934 SYSTEM_LINKS *font_link, *system_font_link;
1935 CHILD_FONT *child_font;
1936 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1937 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1938 FONTSIGNATURE fs;
1939 Family *family;
1940 Face *face;
1941 FontSubst *psub;
1943 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1945 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1946 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1947 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1948 val_len = max_val + 1;
1949 data_len = max_data;
1950 index = 0;
1951 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1953 memset(&fs, 0, sizeof(fs));
1954 psub = get_font_subst(&font_subst_list, value, -1);
1955 /* Don't store fonts that are only substitutes for other fonts */
1956 if(psub)
1958 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1959 goto next;
1961 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1962 font_link->font_name = strdupW(value);
1963 list_init(&font_link->links);
1964 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1966 WCHAR *face_name;
1967 CHILD_FONT *child_font;
1969 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1971 next = entry + strlenW(entry) + 1;
1973 face_name = strchrW(entry, ',');
1974 if(face_name)
1976 *face_name++ = 0;
1977 while(isspaceW(*face_name))
1978 face_name++;
1980 psub = get_font_subst(&font_subst_list, face_name, -1);
1981 if(psub)
1982 face_name = psub->to.name;
1984 face = find_face_from_filename(entry, face_name);
1985 if(!face)
1987 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1988 continue;
1991 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1992 child_font->face = face;
1993 child_font->font = NULL;
1994 fs.fsCsb[0] |= face->fs.fsCsb[0];
1995 fs.fsCsb[1] |= face->fs.fsCsb[1];
1996 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1997 list_add_tail(&font_link->links, &child_font->entry);
1999 family = find_family_from_name(font_link->font_name);
2000 if(family)
2002 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2004 face->fs_links = fs;
2007 list_add_tail(&system_links, &font_link->entry);
2008 next:
2009 val_len = max_val + 1;
2010 data_len = max_data;
2013 HeapFree(GetProcessHeap(), 0, value);
2014 HeapFree(GetProcessHeap(), 0, data);
2015 RegCloseKey(hkey);
2018 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2019 that Tahoma has */
2021 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2022 system_font_link->font_name = strdupW(System);
2023 list_init(&system_font_link->links);
2025 face = find_face_from_filename(tahoma_ttf, Tahoma);
2026 if(face)
2028 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2029 child_font->face = face;
2030 child_font->font = NULL;
2031 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2032 list_add_tail(&system_font_link->links, &child_font->entry);
2034 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2036 if(!strcmpiW(font_link->font_name, Tahoma))
2038 CHILD_FONT *font_link_entry;
2039 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2041 CHILD_FONT *new_child;
2042 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2043 new_child->face = font_link_entry->face;
2044 new_child->font = NULL;
2045 list_add_tail(&system_font_link->links, &new_child->entry);
2047 break;
2050 list_add_tail(&system_links, &system_font_link->entry);
2051 return ret;
2054 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2056 DIR *dir;
2057 struct dirent *dent;
2058 char path[MAX_PATH];
2060 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2062 dir = opendir(dirname);
2063 if(!dir) {
2064 WARN("Can't open directory %s\n", debugstr_a(dirname));
2065 return FALSE;
2067 while((dent = readdir(dir)) != NULL) {
2068 struct stat statbuf;
2070 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2071 continue;
2073 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2075 sprintf(path, "%s/%s", dirname, dent->d_name);
2077 if(stat(path, &statbuf) == -1)
2079 WARN("Can't stat %s\n", debugstr_a(path));
2080 continue;
2082 if(S_ISDIR(statbuf.st_mode))
2083 ReadFontDir(path, external_fonts);
2084 else
2086 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2087 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2088 AddFontFileToList(path, NULL, NULL, addfont_flags);
2091 closedir(dir);
2092 return TRUE;
2095 static void load_fontconfig_fonts(void)
2097 #ifdef SONAME_LIBFONTCONFIG
2098 void *fc_handle = NULL;
2099 FcConfig *config;
2100 FcPattern *pat;
2101 FcObjectSet *os;
2102 FcFontSet *fontset;
2103 int i, len;
2104 char *file;
2105 const char *ext;
2107 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2108 if(!fc_handle) {
2109 TRACE("Wine cannot find the fontconfig library (%s).\n",
2110 SONAME_LIBFONTCONFIG);
2111 return;
2113 #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;}
2114 LOAD_FUNCPTR(FcConfigGetCurrent);
2115 LOAD_FUNCPTR(FcFontList);
2116 LOAD_FUNCPTR(FcFontSetDestroy);
2117 LOAD_FUNCPTR(FcInit);
2118 LOAD_FUNCPTR(FcObjectSetAdd);
2119 LOAD_FUNCPTR(FcObjectSetCreate);
2120 LOAD_FUNCPTR(FcObjectSetDestroy);
2121 LOAD_FUNCPTR(FcPatternCreate);
2122 LOAD_FUNCPTR(FcPatternDestroy);
2123 LOAD_FUNCPTR(FcPatternGetBool);
2124 LOAD_FUNCPTR(FcPatternGetString);
2125 #undef LOAD_FUNCPTR
2127 if(!pFcInit()) return;
2129 config = pFcConfigGetCurrent();
2130 pat = pFcPatternCreate();
2131 os = pFcObjectSetCreate();
2132 pFcObjectSetAdd(os, FC_FILE);
2133 pFcObjectSetAdd(os, FC_SCALABLE);
2134 fontset = pFcFontList(config, pat, os);
2135 if(!fontset) return;
2136 for(i = 0; i < fontset->nfont; i++) {
2137 FcBool scalable;
2139 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2140 continue;
2141 TRACE("fontconfig: %s\n", file);
2143 /* We're just interested in OT/TT fonts for now, so this hack just
2144 picks up the scalable fonts without extensions .pf[ab] to save time
2145 loading every other font */
2147 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2149 TRACE("not scalable\n");
2150 continue;
2153 len = strlen( file );
2154 if(len < 4) continue;
2155 ext = &file[ len - 3 ];
2156 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2157 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2159 pFcFontSetDestroy(fontset);
2160 pFcObjectSetDestroy(os);
2161 pFcPatternDestroy(pat);
2162 sym_not_found:
2163 #endif
2164 return;
2167 static BOOL load_font_from_data_dir(LPCWSTR file)
2169 BOOL ret = FALSE;
2170 const char *data_dir = wine_get_data_dir();
2172 if (!data_dir) data_dir = wine_get_build_dir();
2174 if (data_dir)
2176 INT len;
2177 char *unix_name;
2179 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2181 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2183 strcpy(unix_name, data_dir);
2184 strcat(unix_name, "/fonts/");
2186 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2188 EnterCriticalSection( &freetype_cs );
2189 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2190 LeaveCriticalSection( &freetype_cs );
2191 HeapFree(GetProcessHeap(), 0, unix_name);
2193 return ret;
2196 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2198 static const WCHAR slashW[] = {'\\','\0'};
2199 BOOL ret = FALSE;
2200 WCHAR windowsdir[MAX_PATH];
2201 char *unixname;
2203 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2204 strcatW(windowsdir, fontsW);
2205 strcatW(windowsdir, slashW);
2206 strcatW(windowsdir, file);
2207 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2208 EnterCriticalSection( &freetype_cs );
2209 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2210 LeaveCriticalSection( &freetype_cs );
2211 HeapFree(GetProcessHeap(), 0, unixname);
2213 return ret;
2216 static void load_system_fonts(void)
2218 HKEY hkey;
2219 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2220 const WCHAR * const *value;
2221 DWORD dlen, type;
2222 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2223 char *unixname;
2225 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2226 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2227 strcatW(windowsdir, fontsW);
2228 for(value = SystemFontValues; *value; value++) {
2229 dlen = sizeof(data);
2230 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2231 type == REG_SZ) {
2232 BOOL added = FALSE;
2234 sprintfW(pathW, fmtW, windowsdir, data);
2235 if((unixname = wine_get_unix_file_name(pathW))) {
2236 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2237 HeapFree(GetProcessHeap(), 0, unixname);
2239 if (!added)
2240 load_font_from_data_dir(data);
2243 RegCloseKey(hkey);
2247 /*************************************************************
2249 * This adds registry entries for any externally loaded fonts
2250 * (fonts from fontconfig or FontDirs). It also deletes entries
2251 * of no longer existing fonts.
2254 static void update_reg_entries(void)
2256 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2257 LPWSTR valueW;
2258 DWORD len, len_fam;
2259 Family *family;
2260 Face *face;
2261 struct list *family_elem_ptr, *face_elem_ptr;
2262 WCHAR *file;
2263 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2264 static const WCHAR spaceW[] = {' ', '\0'};
2265 char *path;
2267 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2268 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2269 ERR("Can't create Windows font reg key\n");
2270 goto end;
2273 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2274 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2275 ERR("Can't create Windows font reg key\n");
2276 goto end;
2279 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2280 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2281 ERR("Can't create external font reg key\n");
2282 goto end;
2285 /* enumerate the fonts and add external ones to the two keys */
2287 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2288 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2289 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2290 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2291 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2292 if(!face->external) continue;
2293 len = len_fam;
2294 if (!(face->ntmFlags & NTM_REGULAR))
2295 len = len_fam + strlenW(face->StyleName) + 1;
2296 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2297 strcpyW(valueW, family->FamilyName);
2298 if(len != len_fam) {
2299 strcatW(valueW, spaceW);
2300 strcatW(valueW, face->StyleName);
2302 strcatW(valueW, TrueType);
2304 file = wine_get_dos_file_name(face->file);
2305 if(file)
2306 len = strlenW(file) + 1;
2307 else
2309 if((path = strrchr(face->file, '/')) == NULL)
2310 path = face->file;
2311 else
2312 path++;
2313 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2315 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2316 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2318 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2319 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2320 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2322 HeapFree(GetProcessHeap(), 0, file);
2323 HeapFree(GetProcessHeap(), 0, valueW);
2326 end:
2327 if(external_key) RegCloseKey(external_key);
2328 if(win9x_key) RegCloseKey(win9x_key);
2329 if(winnt_key) RegCloseKey(winnt_key);
2330 return;
2333 static void delete_external_font_keys(void)
2335 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2336 DWORD dlen, vlen, datalen, valuelen, i, type;
2337 LPWSTR valueW;
2338 LPVOID data;
2340 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2341 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2342 ERR("Can't create Windows font reg key\n");
2343 goto end;
2346 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2347 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2348 ERR("Can't create Windows font reg key\n");
2349 goto end;
2352 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2353 ERR("Can't create external font reg key\n");
2354 goto end;
2357 /* Delete all external fonts added last time */
2359 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2360 &valuelen, &datalen, NULL, NULL);
2361 valuelen++; /* returned value doesn't include room for '\0' */
2362 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2363 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2365 dlen = datalen * sizeof(WCHAR);
2366 vlen = valuelen;
2367 i = 0;
2368 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2369 &dlen) == ERROR_SUCCESS) {
2371 RegDeleteValueW(winnt_key, valueW);
2372 RegDeleteValueW(win9x_key, valueW);
2373 /* reset dlen and vlen */
2374 dlen = datalen;
2375 vlen = valuelen;
2377 HeapFree(GetProcessHeap(), 0, data);
2378 HeapFree(GetProcessHeap(), 0, valueW);
2380 /* Delete the old external fonts key */
2381 RegCloseKey(external_key);
2382 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2384 end:
2385 if(win9x_key) RegCloseKey(win9x_key);
2386 if(winnt_key) RegCloseKey(winnt_key);
2389 /*************************************************************
2390 * WineEngAddFontResourceEx
2393 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2395 INT ret = 0;
2397 GDI_CheckNotLock();
2399 if (ft_handle) /* do it only if we have freetype up and running */
2401 char *unixname;
2403 if(flags)
2404 FIXME("Ignoring flags %x\n", flags);
2406 if((unixname = wine_get_unix_file_name(file)))
2408 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2410 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2411 EnterCriticalSection( &freetype_cs );
2412 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2413 LeaveCriticalSection( &freetype_cs );
2414 HeapFree(GetProcessHeap(), 0, unixname);
2416 if (!ret && !strchrW(file, '\\')) {
2417 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2418 ret = load_font_from_winfonts_dir(file);
2419 if (!ret) {
2420 /* Try in datadir/fonts (or builddir/fonts),
2421 * needed for Magic the Gathering Online
2423 ret = load_font_from_data_dir(file);
2427 return ret;
2430 /*************************************************************
2431 * WineEngAddFontMemResourceEx
2434 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2436 GDI_CheckNotLock();
2438 if (ft_handle) /* do it only if we have freetype up and running */
2440 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2442 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2443 memcpy(pFontCopy, pbFont, cbFont);
2445 EnterCriticalSection( &freetype_cs );
2446 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2447 LeaveCriticalSection( &freetype_cs );
2449 if (*pcFonts == 0)
2451 TRACE("AddFontToList failed\n");
2452 HeapFree(GetProcessHeap(), 0, pFontCopy);
2453 return 0;
2455 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2456 * For now return something unique but quite random
2458 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2459 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2462 *pcFonts = 0;
2463 return 0;
2466 /*************************************************************
2467 * WineEngRemoveFontResourceEx
2470 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2472 GDI_CheckNotLock();
2473 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2474 return TRUE;
2477 static const struct nls_update_font_list
2479 UINT ansi_cp, oem_cp;
2480 const char *oem, *fixed, *system;
2481 const char *courier, *serif, *small, *sserif;
2482 /* these are for font substitutes */
2483 const char *shelldlg, *tmsrmn;
2484 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2485 *helv_0, *tmsrmn_0;
2486 const struct subst
2488 const char *from, *to;
2489 } arial_0, courier_new_0, times_new_roman_0;
2490 } nls_update_font_list[] =
2492 /* Latin 1 (United States) */
2493 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2494 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2495 "Tahoma","Times New Roman",
2496 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2497 { 0 }, { 0 }, { 0 }
2499 /* Latin 1 (Multilingual) */
2500 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2501 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2502 "Tahoma","Times New Roman", /* FIXME unverified */
2503 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2504 { 0 }, { 0 }, { 0 }
2506 /* Eastern Europe */
2507 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2508 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2509 "Tahoma","Times New Roman", /* FIXME unverified */
2510 "Fixedsys,238", "System,238",
2511 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2512 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2513 { "Arial CE,0", "Arial,238" },
2514 { "Courier New CE,0", "Courier New,238" },
2515 { "Times New Roman CE,0", "Times New Roman,238" }
2517 /* Cyrillic */
2518 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2519 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2520 "Tahoma","Times New Roman", /* FIXME unverified */
2521 "Fixedsys,204", "System,204",
2522 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2523 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2524 { "Arial Cyr,0", "Arial,204" },
2525 { "Courier New Cyr,0", "Courier New,204" },
2526 { "Times New Roman Cyr,0", "Times New Roman,204" }
2528 /* Greek */
2529 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2530 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2531 "Tahoma","Times New Roman", /* FIXME unverified */
2532 "Fixedsys,161", "System,161",
2533 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2534 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2535 { "Arial Greek,0", "Arial,161" },
2536 { "Courier New Greek,0", "Courier New,161" },
2537 { "Times New Roman Greek,0", "Times New Roman,161" }
2539 /* Turkish */
2540 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2541 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2542 "Tahoma","Times New Roman", /* FIXME unverified */
2543 "Fixedsys,162", "System,162",
2544 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2545 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2546 { "Arial Tur,0", "Arial,162" },
2547 { "Courier New Tur,0", "Courier New,162" },
2548 { "Times New Roman Tur,0", "Times New Roman,162" }
2550 /* Hebrew */
2551 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2552 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2553 "Tahoma","Times New Roman", /* FIXME unverified */
2554 "Fixedsys,177", "System,177",
2555 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2556 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2557 { 0 }, { 0 }, { 0 }
2559 /* Arabic */
2560 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2561 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2562 "Tahoma","Times New Roman", /* FIXME unverified */
2563 "Fixedsys,178", "System,178",
2564 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2565 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2566 { 0 }, { 0 }, { 0 }
2568 /* Baltic */
2569 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2570 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2571 "Tahoma","Times New Roman", /* FIXME unverified */
2572 "Fixedsys,186", "System,186",
2573 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2574 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2575 { "Arial Baltic,0", "Arial,186" },
2576 { "Courier New Baltic,0", "Courier New,186" },
2577 { "Times New Roman Baltic,0", "Times New Roman,186" }
2579 /* Vietnamese */
2580 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2581 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2582 "Tahoma","Times New Roman", /* FIXME unverified */
2583 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2584 { 0 }, { 0 }, { 0 }
2586 /* Thai */
2587 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2588 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2589 "Tahoma","Times New Roman", /* FIXME unverified */
2590 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2591 { 0 }, { 0 }, { 0 }
2593 /* Japanese */
2594 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2595 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2596 "MS UI Gothic","MS Serif",
2597 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2598 { 0 }, { 0 }, { 0 }
2600 /* Chinese Simplified */
2601 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2602 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2603 "SimSun", "NSimSun",
2604 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2605 { 0 }, { 0 }, { 0 }
2607 /* Korean */
2608 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2609 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2610 "Gulim", "Batang",
2611 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2612 { 0 }, { 0 }, { 0 }
2614 /* Chinese Traditional */
2615 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2616 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2617 "PMingLiU", "MingLiU",
2618 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2619 { 0 }, { 0 }, { 0 }
2623 static const WCHAR *font_links_list[] =
2625 Lucida_Sans_Unicode,
2626 Microsoft_Sans_Serif,
2627 Tahoma
2630 static const struct font_links_defaults_list
2632 /* Keyed off substitution for "MS Shell Dlg" */
2633 const WCHAR *shelldlg;
2634 /* Maximum of four substitutes, plus terminating NULL pointer */
2635 const WCHAR *substitutes[5];
2636 } font_links_defaults_list[] =
2638 /* Non East-Asian */
2639 { Tahoma, /* FIXME unverified ordering */
2640 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2642 /* Below lists are courtesy of
2643 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2645 /* Japanese */
2646 { MS_UI_Gothic,
2647 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2649 /* Chinese Simplified */
2650 { SimSun,
2651 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2653 /* Korean */
2654 { Gulim,
2655 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2657 /* Chinese Traditional */
2658 { PMingLiU,
2659 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2663 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2665 return ( ansi_cp == 932 /* CP932 for Japanese */
2666 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2667 || ansi_cp == 949 /* CP949 for Korean */
2668 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2671 static inline HKEY create_fonts_NT_registry_key(void)
2673 HKEY hkey = 0;
2675 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2676 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2677 return hkey;
2680 static inline HKEY create_fonts_9x_registry_key(void)
2682 HKEY hkey = 0;
2684 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2685 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2686 return hkey;
2689 static inline HKEY create_config_fonts_registry_key(void)
2691 HKEY hkey = 0;
2693 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2694 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2695 return hkey;
2698 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2700 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2701 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2702 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2703 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2706 static void set_value_key(HKEY hkey, const char *name, const char *value)
2708 if (value)
2709 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2710 else if (name)
2711 RegDeleteValueA(hkey, name);
2714 static void update_font_info(void)
2716 char buf[40], cpbuf[40];
2717 DWORD len, type;
2718 HKEY hkey = 0;
2719 UINT i, ansi_cp = 0, oem_cp = 0;
2720 BOOL done = FALSE;
2722 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2723 return;
2725 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2726 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2727 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2728 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2729 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2731 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2732 if (is_dbcs_ansi_cp(ansi_cp))
2733 use_default_fallback = TRUE;
2735 len = sizeof(buf);
2736 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2738 if (!strcmp( buf, cpbuf )) /* already set correctly */
2740 RegCloseKey(hkey);
2741 return;
2743 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2745 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2747 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2748 RegCloseKey(hkey);
2750 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2752 HKEY hkey;
2754 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2755 nls_update_font_list[i].oem_cp == oem_cp)
2757 hkey = create_config_fonts_registry_key();
2758 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2759 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2760 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2761 RegCloseKey(hkey);
2763 hkey = create_fonts_NT_registry_key();
2764 add_font_list(hkey, &nls_update_font_list[i]);
2765 RegCloseKey(hkey);
2767 hkey = create_fonts_9x_registry_key();
2768 add_font_list(hkey, &nls_update_font_list[i]);
2769 RegCloseKey(hkey);
2771 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2773 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2774 strlen(nls_update_font_list[i].shelldlg)+1);
2775 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2776 strlen(nls_update_font_list[i].tmsrmn)+1);
2778 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2779 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2780 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2781 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2782 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2783 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2784 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2785 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2787 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2788 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2789 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2791 RegCloseKey(hkey);
2793 done = TRUE;
2795 else
2797 /* Delete the FontSubstitutes from other locales */
2798 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2800 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2801 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2802 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2803 RegCloseKey(hkey);
2807 if (!done)
2808 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2810 /* Clear out system links */
2811 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2814 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2816 const WCHAR *value;
2817 int i;
2818 FontSubst *psub;
2819 Family *family;
2820 Face *face;
2821 const char *file;
2822 WCHAR *fileW;
2823 int fileLen;
2824 WCHAR buff[MAX_PATH];
2825 WCHAR *data;
2826 int entryLen;
2828 static const WCHAR comma[] = {',',0};
2830 RegDeleteValueW(hkey, name);
2831 if (values)
2833 data = buff;
2834 data[0] = '\0';
2835 for (i = 0; values[i] != NULL; i++)
2837 value = values[i];
2838 if (!strcmpiW(name,value))
2839 continue;
2840 psub = get_font_subst(&font_subst_list, value, -1);
2841 if(psub)
2842 value = psub->to.name;
2843 family = find_family_from_name(value);
2844 if (!family)
2845 continue;
2846 file = NULL;
2847 /* Use first extant filename for this Family */
2848 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2850 if (!face->file)
2851 continue;
2852 file = strrchr(face->file, '/');
2853 if (!file)
2854 file = face->file;
2855 else
2856 file++;
2857 break;
2859 if (!file)
2860 continue;
2861 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2862 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2863 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2864 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2865 if (sizeof(buff)-(data-buff) < entryLen + 1)
2867 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2868 HeapFree(GetProcessHeap(), 0, fileW);
2869 break;
2871 strcpyW(data, fileW);
2872 strcatW(data, comma);
2873 strcatW(data, value);
2874 data += entryLen;
2875 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2876 HeapFree(GetProcessHeap(), 0, fileW);
2878 if (data != buff)
2880 *data='\0';
2881 data++;
2882 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2883 } else
2884 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2885 } else
2886 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2889 static void update_system_links(void)
2891 HKEY hkey = 0;
2892 UINT i, j;
2893 BOOL done = FALSE;
2894 DWORD disposition;
2895 FontSubst *psub;
2897 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2899 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2901 if (disposition == REG_OPENED_EXISTING_KEY)
2903 TRACE("SystemLink key already exists, doing nothing\n");
2904 RegCloseKey(hkey);
2905 return;
2908 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2909 if (!psub) {
2910 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2911 RegCloseKey(hkey);
2912 return;
2915 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2917 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2919 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2920 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2922 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2923 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2924 done = TRUE;
2926 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2928 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2931 RegCloseKey(hkey);
2932 if (!done)
2933 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2934 } else
2935 WARN("failed to create SystemLink key\n");
2939 static BOOL init_freetype(void)
2941 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2942 if(!ft_handle) {
2943 WINE_MESSAGE(
2944 "Wine cannot find the FreeType font library. To enable Wine to\n"
2945 "use TrueType fonts please install a version of FreeType greater than\n"
2946 "or equal to 2.0.5.\n"
2947 "http://www.freetype.org\n");
2948 return FALSE;
2951 #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;}
2953 LOAD_FUNCPTR(FT_Vector_Unit)
2954 LOAD_FUNCPTR(FT_Done_Face)
2955 LOAD_FUNCPTR(FT_Get_Char_Index)
2956 LOAD_FUNCPTR(FT_Get_Module)
2957 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2958 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2959 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2960 LOAD_FUNCPTR(FT_Init_FreeType)
2961 LOAD_FUNCPTR(FT_Load_Glyph)
2962 LOAD_FUNCPTR(FT_Matrix_Multiply)
2963 #ifndef FT_MULFIX_INLINED
2964 LOAD_FUNCPTR(FT_MulFix)
2965 #endif
2966 LOAD_FUNCPTR(FT_New_Face)
2967 LOAD_FUNCPTR(FT_New_Memory_Face)
2968 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2969 LOAD_FUNCPTR(FT_Outline_Transform)
2970 LOAD_FUNCPTR(FT_Outline_Translate)
2971 LOAD_FUNCPTR(FT_Select_Charmap)
2972 LOAD_FUNCPTR(FT_Set_Charmap)
2973 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2974 LOAD_FUNCPTR(FT_Vector_Transform)
2975 LOAD_FUNCPTR(FT_Render_Glyph)
2977 #undef LOAD_FUNCPTR
2978 /* Don't warn if these ones are missing */
2979 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2980 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2981 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2982 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2983 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2984 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2985 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2986 #endif
2987 #ifdef HAVE_FREETYPE_FTWINFNT_H
2988 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2989 #endif
2990 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2991 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2992 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2993 <= 2.0.3 has FT_Sqrt64 */
2994 goto sym_not_found;
2997 if(pFT_Init_FreeType(&library) != 0) {
2998 ERR("Can't init FreeType library\n");
2999 wine_dlclose(ft_handle, NULL, 0);
3000 ft_handle = NULL;
3001 return FALSE;
3003 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
3004 if (pFT_Library_Version)
3005 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3007 if (FT_Version.major<=0)
3009 FT_Version.major=2;
3010 FT_Version.minor=0;
3011 FT_Version.patch=5;
3013 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3014 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3015 ((FT_Version.minor << 8) & 0x00ff00) |
3016 ((FT_Version.patch ) & 0x0000ff);
3018 return TRUE;
3020 sym_not_found:
3021 WINE_MESSAGE(
3022 "Wine cannot find certain functions that it needs inside the FreeType\n"
3023 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3024 "FreeType to at least version 2.0.5.\n"
3025 "http://www.freetype.org\n");
3026 wine_dlclose(ft_handle, NULL, 0);
3027 ft_handle = NULL;
3028 return FALSE;
3031 static void init_font_list(void)
3033 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3034 static const WCHAR pathW[] = {'P','a','t','h',0};
3035 HKEY hkey;
3036 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3037 WCHAR windowsdir[MAX_PATH];
3038 char *unixname;
3039 const char *data_dir;
3041 delete_external_font_keys();
3043 /* load the system bitmap fonts */
3044 load_system_fonts();
3046 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3047 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3048 strcatW(windowsdir, fontsW);
3049 if((unixname = wine_get_unix_file_name(windowsdir)))
3051 ReadFontDir(unixname, FALSE);
3052 HeapFree(GetProcessHeap(), 0, unixname);
3055 /* load the system truetype fonts */
3056 data_dir = wine_get_data_dir();
3057 if (!data_dir) data_dir = wine_get_build_dir();
3058 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3060 strcpy(unixname, data_dir);
3061 strcat(unixname, "/fonts/");
3062 ReadFontDir(unixname, TRUE);
3063 HeapFree(GetProcessHeap(), 0, unixname);
3066 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3067 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3068 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3069 will skip these. */
3070 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3071 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3072 &hkey) == ERROR_SUCCESS)
3074 LPWSTR data, valueW;
3075 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3076 &valuelen, &datalen, NULL, NULL);
3078 valuelen++; /* returned value doesn't include room for '\0' */
3079 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3080 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3081 if (valueW && data)
3083 dlen = datalen * sizeof(WCHAR);
3084 vlen = valuelen;
3085 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3086 &dlen) == ERROR_SUCCESS)
3088 if(data[0] && (data[1] == ':'))
3090 if((unixname = wine_get_unix_file_name(data)))
3092 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3093 HeapFree(GetProcessHeap(), 0, unixname);
3096 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3098 WCHAR pathW[MAX_PATH];
3099 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3100 BOOL added = FALSE;
3102 sprintfW(pathW, fmtW, windowsdir, data);
3103 if((unixname = wine_get_unix_file_name(pathW)))
3105 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3106 HeapFree(GetProcessHeap(), 0, unixname);
3108 if (!added)
3109 load_font_from_data_dir(data);
3111 /* reset dlen and vlen */
3112 dlen = datalen;
3113 vlen = valuelen;
3116 HeapFree(GetProcessHeap(), 0, data);
3117 HeapFree(GetProcessHeap(), 0, valueW);
3118 RegCloseKey(hkey);
3121 load_fontconfig_fonts();
3123 /* then look in any directories that we've specified in the config file */
3124 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3125 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3127 DWORD len;
3128 LPWSTR valueW;
3129 LPSTR valueA, ptr;
3131 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3133 len += sizeof(WCHAR);
3134 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3135 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3137 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3138 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3139 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3140 TRACE( "got font path %s\n", debugstr_a(valueA) );
3141 ptr = valueA;
3142 while (ptr)
3144 LPSTR next = strchr( ptr, ':' );
3145 if (next) *next++ = 0;
3146 ReadFontDir( ptr, TRUE );
3147 ptr = next;
3149 HeapFree( GetProcessHeap(), 0, valueA );
3151 HeapFree( GetProcessHeap(), 0, valueW );
3153 RegCloseKey(hkey);
3157 static BOOL move_to_front(const WCHAR *name)
3159 Family *family, *cursor2;
3160 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3162 if(!strcmpiW(family->FamilyName, name))
3164 list_remove(&family->entry);
3165 list_add_head(&font_list, &family->entry);
3166 return TRUE;
3169 return FALSE;
3172 static const WCHAR arial[] = {'A','r','i','a','l',0};
3173 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
3174 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};
3175 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};
3176 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
3177 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
3179 static void reorder_font_list(void)
3181 if(!move_to_front(times_new_roman))
3182 move_to_front(bitstream_vera_serif);
3184 if(!move_to_front(courier_new))
3185 move_to_front(bitstream_vera_sans_mono);
3187 if(!move_to_front(arial))
3188 move_to_front(bitstream_vera_sans);
3191 /*************************************************************
3192 * WineEngInit
3194 * Initialize FreeType library and create a list of available faces
3196 BOOL WineEngInit(void)
3198 HKEY hkey_font_cache;
3199 DWORD disposition;
3200 HANDLE font_mutex;
3202 /* update locale dependent font info in registry */
3203 update_font_info();
3205 if(!init_freetype()) return FALSE;
3207 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3209 ERR("Failed to create font mutex\n");
3210 return FALSE;
3212 WaitForSingleObject(font_mutex, INFINITE);
3214 create_font_cache_key(&hkey_font_cache, &disposition);
3216 if(disposition == REG_CREATED_NEW_KEY)
3217 init_font_list();
3218 else
3219 load_font_list_from_cache(hkey_font_cache);
3221 RegCloseKey(hkey_font_cache);
3223 reorder_font_list();
3225 DumpFontList();
3226 LoadSubstList();
3227 DumpSubstList();
3228 LoadReplaceList();
3230 if(disposition == REG_CREATED_NEW_KEY)
3231 update_reg_entries();
3233 update_system_links();
3234 init_system_links();
3236 ReleaseMutex(font_mutex);
3237 return TRUE;
3241 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3243 TT_OS2 *pOS2;
3244 TT_HoriHeader *pHori;
3246 LONG ppem;
3248 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3249 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3251 if(height == 0) height = 16;
3253 /* Calc. height of EM square:
3255 * For +ve lfHeight we have
3256 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3257 * Re-arranging gives:
3258 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3260 * For -ve lfHeight we have
3261 * |lfHeight| = ppem
3262 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3263 * with il = winAscent + winDescent - units_per_em]
3267 if(height > 0) {
3268 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3269 ppem = MulDiv(ft_face->units_per_EM, height,
3270 pHori->Ascender - pHori->Descender);
3271 else
3272 ppem = MulDiv(ft_face->units_per_EM, height,
3273 pOS2->usWinAscent + pOS2->usWinDescent);
3275 else
3276 ppem = -height;
3278 return ppem;
3281 static struct font_mapping *map_font_file( const char *name )
3283 struct font_mapping *mapping;
3284 struct stat st;
3285 int fd;
3287 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3288 if (fstat( fd, &st ) == -1) goto error;
3290 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3292 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3294 mapping->refcount++;
3295 close( fd );
3296 return mapping;
3299 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3300 goto error;
3302 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3303 close( fd );
3305 if (mapping->data == MAP_FAILED)
3307 HeapFree( GetProcessHeap(), 0, mapping );
3308 return NULL;
3310 mapping->refcount = 1;
3311 mapping->dev = st.st_dev;
3312 mapping->ino = st.st_ino;
3313 mapping->size = st.st_size;
3314 list_add_tail( &mappings_list, &mapping->entry );
3315 return mapping;
3317 error:
3318 close( fd );
3319 return NULL;
3322 static void unmap_font_file( struct font_mapping *mapping )
3324 if (!--mapping->refcount)
3326 list_remove( &mapping->entry );
3327 munmap( mapping->data, mapping->size );
3328 HeapFree( GetProcessHeap(), 0, mapping );
3332 static LONG load_VDMX(GdiFont*, LONG);
3334 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3336 FT_Error err;
3337 FT_Face ft_face;
3338 void *data_ptr;
3339 DWORD data_size;
3341 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3343 if (face->file)
3345 if (!(font->mapping = map_font_file( face->file )))
3347 WARN("failed to map %s\n", debugstr_a(face->file));
3348 return 0;
3350 data_ptr = font->mapping->data;
3351 data_size = font->mapping->size;
3353 else
3355 data_ptr = face->font_data_ptr;
3356 data_size = face->font_data_size;
3359 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3360 if(err) {
3361 ERR("FT_New_Face rets %d\n", err);
3362 return 0;
3365 /* set it here, as load_VDMX needs it */
3366 font->ft_face = ft_face;
3368 if(FT_IS_SCALABLE(ft_face)) {
3369 /* load the VDMX table if we have one */
3370 font->ppem = load_VDMX(font, height);
3371 if(font->ppem == 0)
3372 font->ppem = calc_ppem_for_height(ft_face, height);
3373 TRACE("height %d => ppem %d\n", height, font->ppem);
3375 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3376 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3377 } else {
3378 font->ppem = height;
3379 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3380 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3382 return ft_face;
3386 static int get_nearest_charset(Face *face, int *cp)
3388 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3389 a single face with the requested charset. The idea is to check if
3390 the selected font supports the current ANSI codepage, if it does
3391 return the corresponding charset, else return the first charset */
3393 CHARSETINFO csi;
3394 int acp = GetACP(), i;
3395 DWORD fs0;
3397 *cp = acp;
3398 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3399 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3400 return csi.ciCharset;
3402 for(i = 0; i < 32; i++) {
3403 fs0 = 1L << i;
3404 if(face->fs.fsCsb[0] & fs0) {
3405 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3406 *cp = csi.ciACP;
3407 return csi.ciCharset;
3409 else
3410 FIXME("TCI failing on %x\n", fs0);
3414 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3415 face->fs.fsCsb[0], face->file);
3416 *cp = acp;
3417 return DEFAULT_CHARSET;
3420 static GdiFont *alloc_font(void)
3422 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3423 ret->gmsize = 1;
3424 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3425 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3426 ret->potm = NULL;
3427 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3428 ret->total_kern_pairs = (DWORD)-1;
3429 ret->kern_pairs = NULL;
3430 list_init(&ret->hfontlist);
3431 list_init(&ret->child_fonts);
3432 return ret;
3435 static void free_font(GdiFont *font)
3437 struct list *cursor, *cursor2;
3438 DWORD i;
3440 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3442 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3443 list_remove(cursor);
3444 if(child->font)
3445 free_font(child->font);
3446 HeapFree(GetProcessHeap(), 0, child);
3449 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3451 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3452 DeleteObject(hfontlist->hfont);
3453 list_remove(&hfontlist->entry);
3454 HeapFree(GetProcessHeap(), 0, hfontlist);
3457 if (font->ft_face) pFT_Done_Face(font->ft_face);
3458 if (font->mapping) unmap_font_file( font->mapping );
3459 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3460 HeapFree(GetProcessHeap(), 0, font->potm);
3461 HeapFree(GetProcessHeap(), 0, font->name);
3462 for (i = 0; i < font->gmsize; i++)
3463 HeapFree(GetProcessHeap(),0,font->gm[i]);
3464 HeapFree(GetProcessHeap(), 0, font->gm);
3465 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3466 HeapFree(GetProcessHeap(), 0, font);
3470 /*************************************************************
3471 * load_VDMX
3473 * load the vdmx entry for the specified height
3476 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3477 ( ( (FT_ULong)_x4 << 24 ) | \
3478 ( (FT_ULong)_x3 << 16 ) | \
3479 ( (FT_ULong)_x2 << 8 ) | \
3480 (FT_ULong)_x1 )
3482 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3484 typedef struct {
3485 BYTE bCharSet;
3486 BYTE xRatio;
3487 BYTE yStartRatio;
3488 BYTE yEndRatio;
3489 } Ratios;
3491 typedef struct {
3492 WORD recs;
3493 BYTE startsz;
3494 BYTE endsz;
3495 } VDMX_group;
3497 static LONG load_VDMX(GdiFont *font, LONG height)
3499 WORD hdr[3], tmp;
3500 VDMX_group group;
3501 BYTE devXRatio, devYRatio;
3502 USHORT numRecs, numRatios;
3503 DWORD result, offset = -1;
3504 LONG ppem = 0;
3505 int i;
3507 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3509 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3510 return ppem;
3512 /* FIXME: need the real device aspect ratio */
3513 devXRatio = 1;
3514 devYRatio = 1;
3516 numRecs = GET_BE_WORD(hdr[1]);
3517 numRatios = GET_BE_WORD(hdr[2]);
3519 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3520 for(i = 0; i < numRatios; i++) {
3521 Ratios ratio;
3523 offset = (3 * 2) + (i * sizeof(Ratios));
3524 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3525 offset = -1;
3527 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3529 if((ratio.xRatio == 0 &&
3530 ratio.yStartRatio == 0 &&
3531 ratio.yEndRatio == 0) ||
3532 (devXRatio == ratio.xRatio &&
3533 devYRatio >= ratio.yStartRatio &&
3534 devYRatio <= ratio.yEndRatio))
3536 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3537 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3538 offset = GET_BE_WORD(tmp);
3539 break;
3543 if(offset == -1) {
3544 FIXME("No suitable ratio found\n");
3545 return ppem;
3548 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3549 USHORT recs;
3550 BYTE startsz, endsz;
3551 WORD *vTable;
3553 recs = GET_BE_WORD(group.recs);
3554 startsz = group.startsz;
3555 endsz = group.endsz;
3557 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3559 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3560 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3561 if(result == GDI_ERROR) {
3562 FIXME("Failed to retrieve vTable\n");
3563 goto end;
3566 if(height > 0) {
3567 for(i = 0; i < recs; i++) {
3568 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3569 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3570 ppem = GET_BE_WORD(vTable[i * 3]);
3572 if(yMax + -yMin == height) {
3573 font->yMax = yMax;
3574 font->yMin = yMin;
3575 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3576 break;
3578 if(yMax + -yMin > height) {
3579 if(--i < 0) {
3580 ppem = 0;
3581 goto end; /* failed */
3583 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3584 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3585 ppem = GET_BE_WORD(vTable[i * 3]);
3586 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3587 break;
3590 if(!font->yMax) {
3591 ppem = 0;
3592 TRACE("ppem not found for height %d\n", height);
3595 end:
3596 HeapFree(GetProcessHeap(), 0, vTable);
3599 return ppem;
3602 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3604 if(font->font_desc.hash != fd->hash) return TRUE;
3605 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3606 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3607 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3608 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3611 static void calc_hash(FONT_DESC *pfd)
3613 DWORD hash = 0, *ptr, two_chars;
3614 WORD *pwc;
3615 unsigned int i;
3617 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3618 hash ^= *ptr;
3619 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3620 hash ^= *ptr;
3621 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3622 two_chars = *ptr;
3623 pwc = (WCHAR *)&two_chars;
3624 if(!*pwc) break;
3625 *pwc = toupperW(*pwc);
3626 pwc++;
3627 *pwc = toupperW(*pwc);
3628 hash ^= two_chars;
3629 if(!*pwc) break;
3631 hash ^= !pfd->can_use_bitmap;
3632 pfd->hash = hash;
3633 return;
3636 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3638 GdiFont *ret;
3639 FONT_DESC fd;
3640 HFONTLIST *hflist;
3641 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3643 fd.lf = *plf;
3644 fd.matrix = *pmat;
3645 fd.can_use_bitmap = can_use_bitmap;
3646 calc_hash(&fd);
3648 /* try the child list */
3649 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3650 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3651 if(!fontcmp(ret, &fd)) {
3652 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3653 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3654 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3655 if(hflist->hfont == hfont)
3656 return ret;
3661 /* try the in-use list */
3662 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3663 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3664 if(!fontcmp(ret, &fd)) {
3665 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3666 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3667 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3668 if(hflist->hfont == hfont)
3669 return ret;
3671 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3672 hflist->hfont = hfont;
3673 list_add_head(&ret->hfontlist, &hflist->entry);
3674 return ret;
3678 /* then the unused list */
3679 font_elem_ptr = list_head(&unused_gdi_font_list);
3680 while(font_elem_ptr) {
3681 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3682 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3683 if(!fontcmp(ret, &fd)) {
3684 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3685 assert(list_empty(&ret->hfontlist));
3686 TRACE("Found %p in unused list\n", ret);
3687 list_remove(&ret->entry);
3688 list_add_head(&gdi_font_list, &ret->entry);
3689 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3690 hflist->hfont = hfont;
3691 list_add_head(&ret->hfontlist, &hflist->entry);
3692 return ret;
3695 return NULL;
3698 static void add_to_cache(GdiFont *font)
3700 static DWORD cache_num = 1;
3702 font->cache_num = cache_num++;
3703 list_add_head(&gdi_font_list, &font->entry);
3706 /*************************************************************
3707 * create_child_font_list
3709 static BOOL create_child_font_list(GdiFont *font)
3711 BOOL ret = FALSE;
3712 SYSTEM_LINKS *font_link;
3713 CHILD_FONT *font_link_entry, *new_child;
3714 FontSubst *psub;
3715 WCHAR* font_name;
3717 psub = get_font_subst(&font_subst_list, font->name, -1);
3718 font_name = psub ? psub->to.name : font->name;
3719 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3721 if(!strcmpiW(font_link->font_name, font_name))
3723 TRACE("found entry in system list\n");
3724 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3726 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3727 new_child->face = font_link_entry->face;
3728 new_child->font = NULL;
3729 list_add_tail(&font->child_fonts, &new_child->entry);
3730 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3732 ret = TRUE;
3733 break;
3737 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3738 * Sans Serif. This is how asian windows get default fallbacks for fonts
3740 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3741 font->charset != OEM_CHARSET &&
3742 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3743 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3745 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3747 TRACE("found entry in default fallback list\n");
3748 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3750 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3751 new_child->face = font_link_entry->face;
3752 new_child->font = NULL;
3753 list_add_tail(&font->child_fonts, &new_child->entry);
3754 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3756 ret = TRUE;
3757 break;
3761 return ret;
3764 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3766 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3768 if (pFT_Set_Charmap)
3770 FT_Int i;
3771 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3773 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3775 for (i = 0; i < ft_face->num_charmaps; i++)
3777 if (ft_face->charmaps[i]->encoding == encoding)
3779 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3780 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3782 switch (ft_face->charmaps[i]->platform_id)
3784 default:
3785 cmap_def = ft_face->charmaps[i];
3786 break;
3787 case 0: /* Apple Unicode */
3788 cmap0 = ft_face->charmaps[i];
3789 break;
3790 case 1: /* Macintosh */
3791 cmap1 = ft_face->charmaps[i];
3792 break;
3793 case 2: /* ISO */
3794 cmap2 = ft_face->charmaps[i];
3795 break;
3796 case 3: /* Microsoft */
3797 cmap3 = ft_face->charmaps[i];
3798 break;
3802 if (cmap3) /* prefer Microsoft cmap table */
3803 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3804 else if (cmap1)
3805 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3806 else if (cmap2)
3807 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3808 else if (cmap0)
3809 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3810 else if (cmap_def)
3811 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3813 return ft_err == FT_Err_Ok;
3816 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3819 /*************************************************************
3820 * WineEngCreateFontInstance
3823 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3825 GdiFont *ret;
3826 Face *face, *best, *best_bitmap;
3827 Family *family, *last_resort_family;
3828 struct list *family_elem_ptr, *face_elem_ptr;
3829 INT height, width = 0;
3830 unsigned int score = 0, new_score;
3831 signed int diff = 0, newdiff;
3832 BOOL bd, it, can_use_bitmap;
3833 LOGFONTW lf;
3834 CHARSETINFO csi;
3835 HFONTLIST *hflist;
3836 FMAT2 dcmat;
3837 FontSubst *psub = NULL;
3839 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3840 lf.lfWidth = abs(lf.lfWidth);
3842 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3844 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3845 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3846 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3847 lf.lfEscapement);
3849 if(dc->GraphicsMode == GM_ADVANCED)
3850 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3851 else
3853 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3854 font scaling abilities. */
3855 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3856 dcmat.eM21 = dcmat.eM12 = 0;
3859 /* Try to avoid not necessary glyph transformations */
3860 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3862 lf.lfHeight *= fabs(dcmat.eM11);
3863 lf.lfWidth *= fabs(dcmat.eM11);
3864 dcmat.eM11 = dcmat.eM22 = 1.0;
3867 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3868 dcmat.eM21, dcmat.eM22);
3870 GDI_CheckNotLock();
3871 EnterCriticalSection( &freetype_cs );
3873 /* check the cache first */
3874 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3875 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3876 LeaveCriticalSection( &freetype_cs );
3877 return ret;
3880 TRACE("not in cache\n");
3881 if(list_empty(&font_list)) /* No fonts installed */
3883 TRACE("No fonts installed\n");
3884 LeaveCriticalSection( &freetype_cs );
3885 return NULL;
3888 ret = alloc_font();
3890 ret->font_desc.matrix = dcmat;
3891 ret->font_desc.lf = lf;
3892 ret->font_desc.can_use_bitmap = can_use_bitmap;
3893 calc_hash(&ret->font_desc);
3894 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3895 hflist->hfont = hfont;
3896 list_add_head(&ret->hfontlist, &hflist->entry);
3898 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3899 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3900 original value lfCharSet. Note this is a special case for
3901 Symbol and doesn't happen at least for "Wingdings*" */
3903 if(!strcmpiW(lf.lfFaceName, SymbolW))
3904 lf.lfCharSet = SYMBOL_CHARSET;
3906 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3907 switch(lf.lfCharSet) {
3908 case DEFAULT_CHARSET:
3909 csi.fs.fsCsb[0] = 0;
3910 break;
3911 default:
3912 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3913 csi.fs.fsCsb[0] = 0;
3914 break;
3918 family = NULL;
3919 if(lf.lfFaceName[0] != '\0') {
3920 SYSTEM_LINKS *font_link;
3921 CHILD_FONT *font_link_entry;
3922 LPWSTR FaceName = lf.lfFaceName;
3925 * Check for a leading '@' this signals that the font is being
3926 * requested in tategaki mode (vertical writing substitution) but
3927 * does not affect the fontface that is to be selected.
3929 if (lf.lfFaceName[0]=='@')
3930 FaceName = &lf.lfFaceName[1];
3932 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3934 if(psub) {
3935 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3936 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3937 if (psub->to.charset != -1)
3938 lf.lfCharSet = psub->to.charset;
3941 /* We want a match on name and charset or just name if
3942 charset was DEFAULT_CHARSET. If the latter then
3943 we fixup the returned charset later in get_nearest_charset
3944 where we'll either use the charset of the current ansi codepage
3945 or if that's unavailable the first charset that the font supports.
3947 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3948 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3949 if (!strcmpiW(family->FamilyName, FaceName) ||
3950 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3952 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3953 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3954 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3955 if(face->scalable || can_use_bitmap)
3956 goto found;
3961 /* Search by full face name. */
3962 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3963 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3964 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3965 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3966 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3967 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3969 if(face->scalable || can_use_bitmap)
3970 goto found_face;
3976 * Try check the SystemLink list first for a replacement font.
3977 * We may find good replacements there.
3979 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3981 if(!strcmpiW(font_link->font_name, FaceName) ||
3982 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3984 TRACE("found entry in system list\n");
3985 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3987 face = font_link_entry->face;
3988 family = face->family;
3989 if(csi.fs.fsCsb[0] &
3990 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3992 if(face->scalable || can_use_bitmap)
3993 goto found;
4000 psub = NULL; /* substitution is no more relevant */
4002 /* If requested charset was DEFAULT_CHARSET then try using charset
4003 corresponding to the current ansi codepage */
4004 if (!csi.fs.fsCsb[0])
4006 INT acp = GetACP();
4007 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4008 FIXME("TCI failed on codepage %d\n", acp);
4009 csi.fs.fsCsb[0] = 0;
4010 } else
4011 lf.lfCharSet = csi.ciCharset;
4014 /* Face families are in the top 4 bits of lfPitchAndFamily,
4015 so mask with 0xF0 before testing */
4017 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4018 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4019 strcpyW(lf.lfFaceName, defFixed);
4020 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4021 strcpyW(lf.lfFaceName, defSerif);
4022 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4023 strcpyW(lf.lfFaceName, defSans);
4024 else
4025 strcpyW(lf.lfFaceName, defSans);
4026 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4027 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4028 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4029 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4030 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4031 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4032 if(face->scalable || can_use_bitmap)
4033 goto found;
4038 last_resort_family = NULL;
4039 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4040 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4041 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4042 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4043 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4044 if(face->scalable)
4045 goto found;
4046 if(can_use_bitmap && !last_resort_family)
4047 last_resort_family = family;
4052 if(last_resort_family) {
4053 family = last_resort_family;
4054 csi.fs.fsCsb[0] = 0;
4055 goto found;
4058 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4059 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4060 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4061 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4062 if(face->scalable) {
4063 csi.fs.fsCsb[0] = 0;
4064 WARN("just using first face for now\n");
4065 goto found;
4067 if(can_use_bitmap && !last_resort_family)
4068 last_resort_family = family;
4071 if(!last_resort_family) {
4072 FIXME("can't find a single appropriate font - bailing\n");
4073 free_font(ret);
4074 LeaveCriticalSection( &freetype_cs );
4075 return NULL;
4078 WARN("could only find a bitmap font - this will probably look awful!\n");
4079 family = last_resort_family;
4080 csi.fs.fsCsb[0] = 0;
4082 found:
4083 it = lf.lfItalic ? 1 : 0;
4084 bd = lf.lfWeight > 550 ? 1 : 0;
4086 height = lf.lfHeight;
4088 face = best = best_bitmap = NULL;
4089 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4091 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4093 BOOL italic, bold;
4095 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4096 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4097 new_score = (italic ^ it) + (bold ^ bd);
4098 if(!best || new_score <= score)
4100 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4101 italic, bold, it, bd);
4102 score = new_score;
4103 best = face;
4104 if(best->scalable && score == 0) break;
4105 if(!best->scalable)
4107 if(height > 0)
4108 newdiff = height - (signed int)(best->size.height);
4109 else
4110 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4111 if(!best_bitmap || new_score < score ||
4112 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4114 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4115 diff = newdiff;
4116 best_bitmap = best;
4117 if(score == 0 && diff == 0) break;
4123 if(best)
4124 face = best->scalable ? best : best_bitmap;
4125 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4126 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4128 found_face:
4129 height = lf.lfHeight;
4131 ret->fs = face->fs;
4133 if(csi.fs.fsCsb[0]) {
4134 ret->charset = lf.lfCharSet;
4135 ret->codepage = csi.ciACP;
4137 else
4138 ret->charset = get_nearest_charset(face, &ret->codepage);
4140 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4141 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4143 ret->aveWidth = height ? lf.lfWidth : 0;
4145 if(!face->scalable) {
4146 /* Windows uses integer scaling factors for bitmap fonts */
4147 INT scale, scaled_height;
4148 GdiFont *cachedfont;
4150 /* FIXME: rotation of bitmap fonts is ignored */
4151 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4152 if (ret->aveWidth)
4153 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4154 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4155 dcmat.eM11 = dcmat.eM22 = 1.0;
4156 /* As we changed the matrix, we need to search the cache for the font again,
4157 * otherwise we might explode the cache. */
4158 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4159 TRACE("Found cached font after non-scalable matrix rescale!\n");
4160 free_font( ret );
4161 LeaveCriticalSection( &freetype_cs );
4162 return cachedfont;
4164 calc_hash(&ret->font_desc);
4166 if (height != 0) height = diff;
4167 height += face->size.height;
4169 scale = (height + face->size.height - 1) / face->size.height;
4170 scaled_height = scale * face->size.height;
4171 /* Only jump to the next height if the difference <= 25% original height */
4172 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4173 /* The jump between unscaled and doubled is delayed by 1 */
4174 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4175 ret->scale_y = scale;
4177 width = face->size.x_ppem >> 6;
4178 height = face->size.y_ppem >> 6;
4180 else
4181 ret->scale_y = 1.0;
4182 TRACE("font scale y: %f\n", ret->scale_y);
4184 ret->ft_face = OpenFontFace(ret, face, width, height);
4186 if (!ret->ft_face)
4188 free_font( ret );
4189 LeaveCriticalSection( &freetype_cs );
4190 return 0;
4193 ret->ntmFlags = face->ntmFlags;
4195 if (ret->charset == SYMBOL_CHARSET &&
4196 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4197 /* No ops */
4199 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4200 /* No ops */
4202 else {
4203 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4206 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4207 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4208 ret->underline = lf.lfUnderline ? 0xff : 0;
4209 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4210 create_child_font_list(ret);
4212 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4214 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
4215 if (length != GDI_ERROR)
4217 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4218 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4219 TRACE("Loaded GSUB table of %i bytes\n",length);
4223 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4225 add_to_cache(ret);
4226 LeaveCriticalSection( &freetype_cs );
4227 return ret;
4230 static void dump_gdi_font_list(void)
4232 GdiFont *gdiFont;
4233 struct list *elem_ptr;
4235 TRACE("---------- gdiFont Cache ----------\n");
4236 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4237 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4238 TRACE("gdiFont=%p %s %d\n",
4239 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4242 TRACE("---------- Unused gdiFont Cache ----------\n");
4243 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4244 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4245 TRACE("gdiFont=%p %s %d\n",
4246 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4249 TRACE("---------- Child gdiFont Cache ----------\n");
4250 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4251 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4252 TRACE("gdiFont=%p %s %d\n",
4253 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4257 /*************************************************************
4258 * WineEngDestroyFontInstance
4260 * free the gdiFont associated with this handle
4263 BOOL WineEngDestroyFontInstance(HFONT handle)
4265 GdiFont *gdiFont;
4266 HFONTLIST *hflist;
4267 BOOL ret = FALSE;
4268 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4269 int i = 0;
4271 GDI_CheckNotLock();
4272 EnterCriticalSection( &freetype_cs );
4274 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4276 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4277 while(hfontlist_elem_ptr) {
4278 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4279 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4280 if(hflist->hfont == handle) {
4281 TRACE("removing child font %p from child list\n", gdiFont);
4282 list_remove(&gdiFont->entry);
4283 LeaveCriticalSection( &freetype_cs );
4284 return TRUE;
4289 TRACE("destroying hfont=%p\n", handle);
4290 if(TRACE_ON(font))
4291 dump_gdi_font_list();
4293 font_elem_ptr = list_head(&gdi_font_list);
4294 while(font_elem_ptr) {
4295 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4296 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4298 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4299 while(hfontlist_elem_ptr) {
4300 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4301 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4302 if(hflist->hfont == handle) {
4303 list_remove(&hflist->entry);
4304 HeapFree(GetProcessHeap(), 0, hflist);
4305 ret = TRUE;
4308 if(list_empty(&gdiFont->hfontlist)) {
4309 TRACE("Moving to Unused list\n");
4310 list_remove(&gdiFont->entry);
4311 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4316 font_elem_ptr = list_head(&unused_gdi_font_list);
4317 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4318 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4319 while(font_elem_ptr) {
4320 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4321 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4322 TRACE("freeing %p\n", gdiFont);
4323 list_remove(&gdiFont->entry);
4324 free_font(gdiFont);
4326 LeaveCriticalSection( &freetype_cs );
4327 return ret;
4330 /***************************************************
4331 * create_enum_charset_list
4333 * This function creates charset enumeration list because in DEFAULT_CHARSET
4334 * case, the ANSI codepage's charset takes precedence over other charsets.
4335 * This function works as a filter other than DEFAULT_CHARSET case.
4337 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4339 CHARSETINFO csi;
4340 DWORD n = 0;
4342 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4343 csi.fs.fsCsb[0] != 0) {
4344 list->element[n].mask = csi.fs.fsCsb[0];
4345 list->element[n].charset = csi.ciCharset;
4346 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4347 n++;
4349 else { /* charset is DEFAULT_CHARSET or invalid. */
4350 INT acp, i;
4352 /* Set the current codepage's charset as the first element. */
4353 acp = GetACP();
4354 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4355 csi.fs.fsCsb[0] != 0) {
4356 list->element[n].mask = csi.fs.fsCsb[0];
4357 list->element[n].charset = csi.ciCharset;
4358 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4359 n++;
4362 /* Fill out left elements. */
4363 for (i = 0; i < 32; i++) {
4364 FONTSIGNATURE fs;
4365 fs.fsCsb[0] = 1L << i;
4366 fs.fsCsb[1] = 0;
4367 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4368 continue; /* skip, already added. */
4369 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4370 continue; /* skip, this is an invalid fsCsb bit. */
4372 list->element[n].mask = fs.fsCsb[0];
4373 list->element[n].charset = csi.ciCharset;
4374 list->element[n].name = ElfScriptsW[i];
4375 n++;
4378 list->total = n;
4380 return n;
4383 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4384 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4386 GdiFont *font;
4387 LONG width, height;
4389 if (face->cached_enum_data)
4391 TRACE("Cached\n");
4392 *pelf = face->cached_enum_data->elf;
4393 *pntm = face->cached_enum_data->ntm;
4394 *ptype = face->cached_enum_data->type;
4395 return;
4398 font = alloc_font();
4400 if(face->scalable) {
4401 height = -2048; /* 2048 is the most common em size */
4402 width = 0;
4403 } else {
4404 height = face->size.y_ppem >> 6;
4405 width = face->size.x_ppem >> 6;
4407 font->scale_y = 1.0;
4409 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4411 free_font(font);
4412 return;
4415 font->name = strdupW(face->family->FamilyName);
4416 font->ntmFlags = face->ntmFlags;
4418 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4420 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4422 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4424 lstrcpynW(pelf->elfLogFont.lfFaceName,
4425 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4426 LF_FACESIZE);
4427 lstrcpynW(pelf->elfFullName,
4428 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4429 LF_FULLFACESIZE);
4430 lstrcpynW(pelf->elfStyle,
4431 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4432 LF_FACESIZE);
4434 else
4436 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4438 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4440 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4441 if (face->FullName)
4442 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4443 else
4444 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4445 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4448 pntm->ntmTm.ntmFlags = face->ntmFlags;
4449 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4450 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4451 pntm->ntmFontSig = face->fs;
4453 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4455 pelf->elfLogFont.lfEscapement = 0;
4456 pelf->elfLogFont.lfOrientation = 0;
4457 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4458 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4459 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4460 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4461 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4462 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4463 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4464 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4465 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4466 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4467 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4469 *ptype = 0;
4470 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4471 *ptype |= TRUETYPE_FONTTYPE;
4472 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4473 *ptype |= DEVICE_FONTTYPE;
4474 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4475 *ptype |= RASTER_FONTTYPE;
4477 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4478 if (face->cached_enum_data)
4480 face->cached_enum_data->elf = *pelf;
4481 face->cached_enum_data->ntm = *pntm;
4482 face->cached_enum_data->type = *ptype;
4485 free_font(font);
4488 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4490 struct list *face_elem_ptr;
4492 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4494 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4496 static const WCHAR spaceW[] = { ' ',0 };
4497 WCHAR full_family_name[LF_FULLFACESIZE];
4498 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4500 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4502 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4503 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4504 continue;
4507 strcpyW(full_family_name, family->FamilyName);
4508 strcatW(full_family_name, spaceW);
4509 strcatW(full_family_name, face->StyleName);
4510 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4513 return FALSE;
4516 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4518 static const WCHAR spaceW[] = { ' ',0 };
4519 WCHAR full_family_name[LF_FULLFACESIZE];
4521 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4523 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4525 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4526 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4527 return FALSE;
4530 strcpyW(full_family_name, face->family->FamilyName);
4531 strcatW(full_family_name, spaceW);
4532 strcatW(full_family_name, face->StyleName);
4533 return !strcmpiW(lf->lfFaceName, full_family_name);
4536 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4537 FONTENUMPROCW proc, LPARAM lparam)
4539 ENUMLOGFONTEXW elf;
4540 NEWTEXTMETRICEXW ntm;
4541 DWORD type = 0;
4542 int i;
4544 GetEnumStructs(face, &elf, &ntm, &type);
4545 for(i = 0; i < list->total; i++) {
4546 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4547 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4548 strcpyW(elf.elfScript, OEM_DOSW);
4549 i = 32; /* break out of loop */
4550 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4551 continue;
4552 else {
4553 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4554 if(list->element[i].name)
4555 strcpyW(elf.elfScript, list->element[i].name);
4556 else
4557 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4559 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4560 debugstr_w(elf.elfLogFont.lfFaceName),
4561 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4562 list->element[i].charset, type, debugstr_w(elf.elfScript),
4563 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4564 ntm.ntmTm.ntmFlags);
4565 /* release section before callback (FIXME) */
4566 LeaveCriticalSection( &freetype_cs );
4567 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4568 EnterCriticalSection( &freetype_cs );
4570 return TRUE;
4573 /*************************************************************
4574 * WineEngEnumFonts
4577 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4579 Family *family;
4580 Face *face;
4581 struct list *family_elem_ptr, *face_elem_ptr;
4582 LOGFONTW lf;
4583 struct enum_charset_list enum_charsets;
4585 if (!plf)
4587 lf.lfCharSet = DEFAULT_CHARSET;
4588 lf.lfPitchAndFamily = 0;
4589 lf.lfFaceName[0] = 0;
4590 plf = &lf;
4593 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4595 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4597 GDI_CheckNotLock();
4598 EnterCriticalSection( &freetype_cs );
4599 if(plf->lfFaceName[0]) {
4600 FontSubst *psub;
4601 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4603 if(psub) {
4604 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4605 debugstr_w(psub->to.name));
4606 lf = *plf;
4607 strcpyW(lf.lfFaceName, psub->to.name);
4608 plf = &lf;
4611 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4612 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4613 if(family_matches(family, plf)) {
4614 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4615 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4616 if (!face_matches(face, plf)) continue;
4617 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4621 } else {
4622 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4623 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4624 face_elem_ptr = list_head(&family->faces);
4625 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4626 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4629 LeaveCriticalSection( &freetype_cs );
4630 return 1;
4633 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4635 pt->x.value = vec->x >> 6;
4636 pt->x.fract = (vec->x & 0x3f) << 10;
4637 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4638 pt->y.value = vec->y >> 6;
4639 pt->y.fract = (vec->y & 0x3f) << 10;
4640 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4641 return;
4644 /***************************************************
4645 * According to the MSDN documentation on WideCharToMultiByte,
4646 * certain codepages cannot set the default_used parameter.
4647 * This returns TRUE if the codepage can set that parameter, false else
4648 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4650 static BOOL codepage_sets_default_used(UINT codepage)
4652 switch (codepage)
4654 case CP_UTF7:
4655 case CP_UTF8:
4656 case CP_SYMBOL:
4657 return FALSE;
4658 default:
4659 return TRUE;
4664 * GSUB Table handling functions
4667 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4669 const GSUB_CoverageFormat1* cf1;
4671 cf1 = table;
4673 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4675 int count = GET_BE_WORD(cf1->GlyphCount);
4676 int i;
4677 TRACE("Coverage Format 1, %i glyphs\n",count);
4678 for (i = 0; i < count; i++)
4679 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4680 return i;
4681 return -1;
4683 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4685 const GSUB_CoverageFormat2* cf2;
4686 int i;
4687 int count;
4688 cf2 = (const GSUB_CoverageFormat2*)cf1;
4690 count = GET_BE_WORD(cf2->RangeCount);
4691 TRACE("Coverage Format 2, %i ranges\n",count);
4692 for (i = 0; i < count; i++)
4694 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4695 return -1;
4696 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4697 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4699 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4700 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4703 return -1;
4705 else
4706 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4708 return -1;
4711 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4713 const GSUB_ScriptList *script;
4714 const GSUB_Script *deflt = NULL;
4715 int i;
4716 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4718 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4719 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4721 const GSUB_Script *scr;
4722 int offset;
4724 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4725 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4727 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4728 return scr;
4729 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4730 deflt = scr;
4732 return deflt;
4735 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4737 int i;
4738 int offset;
4739 const GSUB_LangSys *Lang;
4741 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4743 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4745 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4746 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4748 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4749 return Lang;
4751 offset = GET_BE_WORD(script->DefaultLangSys);
4752 if (offset)
4754 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4755 return Lang;
4757 return NULL;
4760 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4762 int i;
4763 const GSUB_FeatureList *feature;
4764 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4766 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4767 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4769 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4770 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4772 const GSUB_Feature *feat;
4773 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4774 return feat;
4777 return NULL;
4780 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4782 int i;
4783 int offset;
4784 const GSUB_LookupList *lookup;
4785 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4787 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4788 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4790 const GSUB_LookupTable *look;
4791 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4792 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4793 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4794 if (GET_BE_WORD(look->LookupType) != 1)
4795 FIXME("We only handle SubType 1\n");
4796 else
4798 int j;
4800 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4802 const GSUB_SingleSubstFormat1 *ssf1;
4803 offset = GET_BE_WORD(look->SubTable[j]);
4804 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4805 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4807 int offset = GET_BE_WORD(ssf1->Coverage);
4808 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4809 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4811 TRACE(" Glyph 0x%x ->",glyph);
4812 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4813 TRACE(" 0x%x\n",glyph);
4816 else
4818 const GSUB_SingleSubstFormat2 *ssf2;
4819 INT index;
4820 INT offset;
4822 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4823 offset = GET_BE_WORD(ssf1->Coverage);
4824 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4825 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4826 TRACE(" Coverage index %i\n",index);
4827 if (index != -1)
4829 TRACE(" Glyph is 0x%x ->",glyph);
4830 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4831 TRACE("0x%x\n",glyph);
4837 return glyph;
4840 static const char* get_opentype_script(const GdiFont *font)
4843 * I am not sure if this is the correct way to generate our script tag
4846 switch (font->charset)
4848 case ANSI_CHARSET: return "latn";
4849 case BALTIC_CHARSET: return "latn"; /* ?? */
4850 case CHINESEBIG5_CHARSET: return "hani";
4851 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4852 case GB2312_CHARSET: return "hani";
4853 case GREEK_CHARSET: return "grek";
4854 case HANGUL_CHARSET: return "hang";
4855 case RUSSIAN_CHARSET: return "cyrl";
4856 case SHIFTJIS_CHARSET: return "kana";
4857 case TURKISH_CHARSET: return "latn"; /* ?? */
4858 case VIETNAMESE_CHARSET: return "latn";
4859 case JOHAB_CHARSET: return "latn"; /* ?? */
4860 case ARABIC_CHARSET: return "arab";
4861 case HEBREW_CHARSET: return "hebr";
4862 case THAI_CHARSET: return "thai";
4863 default: return "latn";
4867 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4869 const GSUB_Header *header;
4870 const GSUB_Script *script;
4871 const GSUB_LangSys *language;
4872 const GSUB_Feature *feature;
4874 if (!font->GSUB_Table)
4875 return glyph;
4877 header = font->GSUB_Table;
4879 script = GSUB_get_script_table(header, get_opentype_script(font));
4880 if (!script)
4882 TRACE("Script not found\n");
4883 return glyph;
4885 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4886 if (!language)
4888 TRACE("Language not found\n");
4889 return glyph;
4891 feature = GSUB_get_feature(header, language, "vrt2");
4892 if (!feature)
4893 feature = GSUB_get_feature(header, language, "vert");
4894 if (!feature)
4896 TRACE("vrt2/vert feature not found\n");
4897 return glyph;
4899 return GSUB_apply_feature(header, feature, glyph);
4902 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4904 FT_UInt glyphId;
4906 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4907 WCHAR wc = (WCHAR)glyph;
4908 BOOL default_used;
4909 BOOL *default_used_pointer;
4910 FT_UInt ret;
4911 char buf;
4912 default_used_pointer = NULL;
4913 default_used = FALSE;
4914 if (codepage_sets_default_used(font->codepage))
4915 default_used_pointer = &default_used;
4916 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4917 ret = 0;
4918 else
4919 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4920 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4921 return get_GSUB_vert_glyph(font,ret);
4924 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4926 if (glyph < 0x100) glyph += 0xf000;
4927 /* there is a number of old pre-Unicode "broken" TTFs, which
4928 do have symbols at U+00XX instead of U+f0XX */
4929 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4930 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4932 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4934 return get_GSUB_vert_glyph(font,glyphId);
4937 /*************************************************************
4938 * WineEngGetGlyphIndices
4941 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4942 LPWORD pgi, DWORD flags)
4944 int i;
4945 WORD default_char;
4946 BOOL got_default = FALSE;
4948 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4950 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4951 got_default = TRUE;
4954 for(i = 0; i < count; i++)
4956 pgi[i] = get_glyph_index(font, lpstr[i]);
4957 if (pgi[i] == 0)
4959 if (!got_default)
4961 if (FT_IS_SFNT(font->ft_face))
4963 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4964 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4966 else
4968 TEXTMETRICW textm;
4969 WineEngGetTextMetrics(font, &textm);
4970 default_char = textm.tmDefaultChar;
4972 got_default = TRUE;
4974 pgi[i] = default_char;
4977 return count;
4980 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4982 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4983 return !memcmp(matrix, &identity, sizeof(FMAT2));
4986 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4988 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4989 return !memcmp(matrix, &identity, sizeof(MAT2));
4992 /*************************************************************
4993 * WineEngGetGlyphOutline
4995 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4996 * except that the first parameter is the HWINEENGFONT of the font in
4997 * question rather than an HDC.
5000 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
5001 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5002 const MAT2* lpmat)
5004 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5005 FT_Face ft_face = incoming_font->ft_face;
5006 GdiFont *font = incoming_font;
5007 FT_UInt glyph_index;
5008 DWORD width, height, pitch, needed = 0;
5009 FT_Bitmap ft_bitmap;
5010 FT_Error err;
5011 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5012 FT_Angle angle = 0;
5013 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5014 double widthRatio = 1.0;
5015 FT_Matrix transMat = identityMat;
5016 FT_Matrix transMatUnrotated;
5017 BOOL needsTransform = FALSE;
5018 BOOL tategaki = (font->GSUB_Table != NULL);
5019 UINT original_index;
5021 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5022 buflen, buf, lpmat);
5024 TRACE("font transform %f %f %f %f\n",
5025 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5026 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5028 GDI_CheckNotLock();
5029 EnterCriticalSection( &freetype_cs );
5031 if(format & GGO_GLYPH_INDEX) {
5032 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5033 original_index = glyph;
5034 format &= ~GGO_GLYPH_INDEX;
5035 } else {
5036 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5037 ft_face = font->ft_face;
5038 original_index = glyph_index;
5041 if(format & GGO_UNHINTED) {
5042 load_flags |= FT_LOAD_NO_HINTING;
5043 format &= ~GGO_UNHINTED;
5046 /* tategaki never appears to happen to lower glyph index */
5047 if (glyph_index < TATEGAKI_LOWER_BOUND )
5048 tategaki = FALSE;
5050 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5051 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5052 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5053 font->gmsize * sizeof(GM*));
5054 } else {
5055 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5056 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5058 *lpgm = FONT_GM(font,original_index)->gm;
5059 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5060 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5061 lpgm->gmCellIncX, lpgm->gmCellIncY);
5062 LeaveCriticalSection( &freetype_cs );
5063 return 1; /* FIXME */
5067 if (!font->gm[original_index / GM_BLOCK_SIZE])
5068 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5070 /* Scaling factor */
5071 if (font->aveWidth)
5073 TEXTMETRICW tm;
5075 WineEngGetTextMetrics(font, &tm);
5077 widthRatio = (double)font->aveWidth;
5078 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5080 else
5081 widthRatio = font->scale_y;
5083 /* Scaling transform */
5084 if (widthRatio != 1.0 || font->scale_y != 1.0)
5086 FT_Matrix scaleMat;
5087 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5088 scaleMat.xy = 0;
5089 scaleMat.yx = 0;
5090 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5092 pFT_Matrix_Multiply(&scaleMat, &transMat);
5093 needsTransform = TRUE;
5096 /* Slant transform */
5097 if (font->fake_italic) {
5098 FT_Matrix slantMat;
5100 slantMat.xx = (1 << 16);
5101 slantMat.xy = ((1 << 16) >> 2);
5102 slantMat.yx = 0;
5103 slantMat.yy = (1 << 16);
5104 pFT_Matrix_Multiply(&slantMat, &transMat);
5105 needsTransform = TRUE;
5108 /* Rotation transform */
5109 transMatUnrotated = transMat;
5110 if(font->orientation && !tategaki) {
5111 FT_Matrix rotationMat;
5112 FT_Vector vecAngle;
5113 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5114 pFT_Vector_Unit(&vecAngle, angle);
5115 rotationMat.xx = vecAngle.x;
5116 rotationMat.xy = -vecAngle.y;
5117 rotationMat.yx = -rotationMat.xy;
5118 rotationMat.yy = rotationMat.xx;
5120 pFT_Matrix_Multiply(&rotationMat, &transMat);
5121 needsTransform = TRUE;
5124 /* World transform */
5125 if (!is_identity_FMAT2(&font->font_desc.matrix))
5127 FT_Matrix worldMat;
5128 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5129 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5130 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5131 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5132 pFT_Matrix_Multiply(&worldMat, &transMat);
5133 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5134 needsTransform = TRUE;
5137 /* Extra transformation specified by caller */
5138 if (!is_identity_MAT2(lpmat))
5140 FT_Matrix extraMat;
5141 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5142 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5143 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5144 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5145 pFT_Matrix_Multiply(&extraMat, &transMat);
5146 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5147 needsTransform = TRUE;
5150 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5151 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5152 format == GGO_GRAY8_BITMAP))
5154 load_flags |= FT_LOAD_NO_BITMAP;
5157 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5159 if(err) {
5160 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5161 LeaveCriticalSection( &freetype_cs );
5162 return GDI_ERROR;
5165 if(!needsTransform) {
5166 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5167 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5168 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5170 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5171 bottom = (ft_face->glyph->metrics.horiBearingY -
5172 ft_face->glyph->metrics.height) & -64;
5173 lpgm->gmCellIncX = adv;
5174 lpgm->gmCellIncY = 0;
5175 } else {
5176 INT xc, yc;
5177 FT_Vector vec;
5179 left = right = 0;
5181 for(xc = 0; xc < 2; xc++) {
5182 for(yc = 0; yc < 2; yc++) {
5183 vec.x = (ft_face->glyph->metrics.horiBearingX +
5184 xc * ft_face->glyph->metrics.width);
5185 vec.y = ft_face->glyph->metrics.horiBearingY -
5186 yc * ft_face->glyph->metrics.height;
5187 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5188 pFT_Vector_Transform(&vec, &transMat);
5189 if(xc == 0 && yc == 0) {
5190 left = right = vec.x;
5191 top = bottom = vec.y;
5192 } else {
5193 if(vec.x < left) left = vec.x;
5194 else if(vec.x > right) right = vec.x;
5195 if(vec.y < bottom) bottom = vec.y;
5196 else if(vec.y > top) top = vec.y;
5200 left = left & -64;
5201 right = (right + 63) & -64;
5202 bottom = bottom & -64;
5203 top = (top + 63) & -64;
5205 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5206 vec.x = ft_face->glyph->metrics.horiAdvance;
5207 vec.y = 0;
5208 pFT_Vector_Transform(&vec, &transMat);
5209 lpgm->gmCellIncX = (vec.x+63) >> 6;
5210 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5212 vec.x = ft_face->glyph->metrics.horiAdvance;
5213 vec.y = 0;
5214 pFT_Vector_Transform(&vec, &transMatUnrotated);
5215 adv = (vec.x+63) >> 6;
5218 lsb = left >> 6;
5219 bbx = (right - left) >> 6;
5220 lpgm->gmBlackBoxX = (right - left) >> 6;
5221 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5222 lpgm->gmptGlyphOrigin.x = left >> 6;
5223 lpgm->gmptGlyphOrigin.y = top >> 6;
5225 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5226 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5227 lpgm->gmCellIncX, lpgm->gmCellIncY);
5229 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5230 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5232 FONT_GM(font,original_index)->gm = *lpgm;
5233 FONT_GM(font,original_index)->adv = adv;
5234 FONT_GM(font,original_index)->lsb = lsb;
5235 FONT_GM(font,original_index)->bbx = bbx;
5236 FONT_GM(font,original_index)->init = TRUE;
5239 if(format == GGO_METRICS)
5241 LeaveCriticalSection( &freetype_cs );
5242 return 1; /* FIXME */
5245 if(ft_face->glyph->format != ft_glyph_format_outline &&
5246 (format == GGO_NATIVE || format == GGO_BEZIER ||
5247 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5248 format == GGO_GRAY8_BITMAP))
5250 TRACE("loaded a bitmap\n");
5251 LeaveCriticalSection( &freetype_cs );
5252 return GDI_ERROR;
5255 switch(format) {
5256 case GGO_BITMAP:
5257 width = lpgm->gmBlackBoxX;
5258 height = lpgm->gmBlackBoxY;
5259 pitch = ((width + 31) >> 5) << 2;
5260 needed = pitch * height;
5262 if(!buf || !buflen) break;
5264 switch(ft_face->glyph->format) {
5265 case ft_glyph_format_bitmap:
5267 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5268 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5269 INT h = ft_face->glyph->bitmap.rows;
5270 while(h--) {
5271 memcpy(dst, src, w);
5272 src += ft_face->glyph->bitmap.pitch;
5273 dst += pitch;
5275 break;
5278 case ft_glyph_format_outline:
5279 ft_bitmap.width = width;
5280 ft_bitmap.rows = height;
5281 ft_bitmap.pitch = pitch;
5282 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5283 ft_bitmap.buffer = buf;
5285 if(needsTransform)
5286 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5288 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5290 /* Note: FreeType will only set 'black' bits for us. */
5291 memset(buf, 0, needed);
5292 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5293 break;
5295 default:
5296 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5297 LeaveCriticalSection( &freetype_cs );
5298 return GDI_ERROR;
5300 break;
5302 case GGO_GRAY2_BITMAP:
5303 case GGO_GRAY4_BITMAP:
5304 case GGO_GRAY8_BITMAP:
5305 case WINE_GGO_GRAY16_BITMAP:
5307 unsigned int mult, row, col;
5308 BYTE *start, *ptr;
5310 width = lpgm->gmBlackBoxX;
5311 height = lpgm->gmBlackBoxY;
5312 pitch = (width + 3) / 4 * 4;
5313 needed = pitch * height;
5315 if(!buf || !buflen) break;
5317 switch(ft_face->glyph->format) {
5318 case ft_glyph_format_bitmap:
5320 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5321 INT h = ft_face->glyph->bitmap.rows;
5322 INT x;
5323 memset( buf, 0, needed );
5324 while(h--) {
5325 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5326 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5327 src += ft_face->glyph->bitmap.pitch;
5328 dst += pitch;
5330 LeaveCriticalSection( &freetype_cs );
5331 return needed;
5333 case ft_glyph_format_outline:
5335 ft_bitmap.width = width;
5336 ft_bitmap.rows = height;
5337 ft_bitmap.pitch = pitch;
5338 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5339 ft_bitmap.buffer = buf;
5341 if(needsTransform)
5342 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5344 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5346 memset(ft_bitmap.buffer, 0, buflen);
5348 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5350 if(format == GGO_GRAY2_BITMAP)
5351 mult = 4;
5352 else if(format == GGO_GRAY4_BITMAP)
5353 mult = 16;
5354 else if(format == GGO_GRAY8_BITMAP)
5355 mult = 64;
5356 else /* format == WINE_GGO_GRAY16_BITMAP */
5358 LeaveCriticalSection( &freetype_cs );
5359 return needed;
5361 break;
5363 default:
5364 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5365 LeaveCriticalSection( &freetype_cs );
5366 return GDI_ERROR;
5369 start = buf;
5370 for(row = 0; row < height; row++) {
5371 ptr = start;
5372 for(col = 0; col < width; col++, ptr++) {
5373 *ptr = (((int)*ptr) * mult + 128) / 256;
5375 start += pitch;
5377 break;
5380 case WINE_GGO_HRGB_BITMAP:
5381 case WINE_GGO_HBGR_BITMAP:
5382 case WINE_GGO_VRGB_BITMAP:
5383 case WINE_GGO_VBGR_BITMAP:
5384 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5386 switch (ft_face->glyph->format)
5388 case FT_GLYPH_FORMAT_BITMAP:
5390 BYTE *src, *dst;
5391 INT src_pitch, x;
5393 width = lpgm->gmBlackBoxX;
5394 height = lpgm->gmBlackBoxY;
5395 pitch = width * 4;
5396 needed = pitch * height;
5398 if (!buf || !buflen) break;
5400 memset(buf, 0, buflen);
5401 dst = buf;
5402 src = ft_face->glyph->bitmap.buffer;
5403 src_pitch = ft_face->glyph->bitmap.pitch;
5405 height = min( height, ft_face->glyph->bitmap.rows );
5406 while ( height-- )
5408 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5410 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5411 ((unsigned int *)dst)[x] = ~0u;
5413 src += src_pitch;
5414 dst += pitch;
5417 break;
5420 case FT_GLYPH_FORMAT_OUTLINE:
5422 unsigned int *dst;
5423 BYTE *src;
5424 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5425 INT x_shift, y_shift;
5426 BOOL rgb;
5427 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5428 FT_Render_Mode render_mode =
5429 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5430 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5432 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5434 if ( render_mode == FT_RENDER_MODE_LCD)
5436 lpgm->gmBlackBoxX += 2;
5437 lpgm->gmptGlyphOrigin.x -= 1;
5439 else
5441 lpgm->gmBlackBoxY += 2;
5442 lpgm->gmptGlyphOrigin.y += 1;
5446 width = lpgm->gmBlackBoxX;
5447 height = lpgm->gmBlackBoxY;
5448 pitch = width * 4;
5449 needed = pitch * height;
5451 if (!buf || !buflen) break;
5453 memset(buf, 0, buflen);
5454 dst = buf;
5455 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5457 if ( needsTransform )
5458 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5460 if ( pFT_Library_SetLcdFilter )
5461 pFT_Library_SetLcdFilter( library, lcdfilter );
5462 pFT_Render_Glyph (ft_face->glyph, render_mode);
5464 src = ft_face->glyph->bitmap.buffer;
5465 src_pitch = ft_face->glyph->bitmap.pitch;
5466 src_width = ft_face->glyph->bitmap.width;
5467 src_height = ft_face->glyph->bitmap.rows;
5469 if ( render_mode == FT_RENDER_MODE_LCD)
5471 rgb_interval = 1;
5472 hmul = 3;
5473 vmul = 1;
5475 else
5477 rgb_interval = src_pitch;
5478 hmul = 1;
5479 vmul = 3;
5482 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5483 if ( x_shift < 0 ) x_shift = 0;
5484 if ( x_shift + (src_width / hmul) > width )
5485 x_shift = width - (src_width / hmul);
5487 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5488 if ( y_shift < 0 ) y_shift = 0;
5489 if ( y_shift + (src_height / vmul) > height )
5490 y_shift = height - (src_height / vmul);
5492 dst += x_shift + y_shift * ( pitch / 4 );
5493 while ( src_height )
5495 for ( x = 0; x < src_width / hmul; x++ )
5497 if ( rgb )
5499 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5500 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5501 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5502 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5504 else
5506 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5507 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5508 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5509 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5512 src += src_pitch * vmul;
5513 dst += pitch / 4;
5514 src_height -= vmul;
5517 break;
5520 default:
5521 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5522 LeaveCriticalSection ( &freetype_cs );
5523 return GDI_ERROR;
5526 break;
5528 #else
5529 LeaveCriticalSection( &freetype_cs );
5530 return GDI_ERROR;
5531 #endif
5533 case GGO_NATIVE:
5535 int contour, point = 0, first_pt;
5536 FT_Outline *outline = &ft_face->glyph->outline;
5537 TTPOLYGONHEADER *pph;
5538 TTPOLYCURVE *ppc;
5539 DWORD pph_start, cpfx, type;
5541 if(buflen == 0) buf = NULL;
5543 if (needsTransform && buf) {
5544 pFT_Outline_Transform(outline, &transMat);
5547 for(contour = 0; contour < outline->n_contours; contour++) {
5548 pph_start = needed;
5549 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5550 first_pt = point;
5551 if(buf) {
5552 pph->dwType = TT_POLYGON_TYPE;
5553 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5555 needed += sizeof(*pph);
5556 point++;
5557 while(point <= outline->contours[contour]) {
5558 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5559 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5560 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5561 cpfx = 0;
5562 do {
5563 if(buf)
5564 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5565 cpfx++;
5566 point++;
5567 } while(point <= outline->contours[contour] &&
5568 (outline->tags[point] & FT_Curve_Tag_On) ==
5569 (outline->tags[point-1] & FT_Curve_Tag_On));
5570 /* At the end of a contour Windows adds the start point, but
5571 only for Beziers */
5572 if(point > outline->contours[contour] &&
5573 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5574 if(buf)
5575 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5576 cpfx++;
5577 } else if(point <= outline->contours[contour] &&
5578 outline->tags[point] & FT_Curve_Tag_On) {
5579 /* add closing pt for bezier */
5580 if(buf)
5581 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5582 cpfx++;
5583 point++;
5585 if(buf) {
5586 ppc->wType = type;
5587 ppc->cpfx = cpfx;
5589 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5591 if(buf)
5592 pph->cb = needed - pph_start;
5594 break;
5596 case GGO_BEZIER:
5598 /* Convert the quadratic Beziers to cubic Beziers.
5599 The parametric eqn for a cubic Bezier is, from PLRM:
5600 r(t) = at^3 + bt^2 + ct + r0
5601 with the control points:
5602 r1 = r0 + c/3
5603 r2 = r1 + (c + b)/3
5604 r3 = r0 + c + b + a
5606 A quadratic Bezier has the form:
5607 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5609 So equating powers of t leads to:
5610 r1 = 2/3 p1 + 1/3 p0
5611 r2 = 2/3 p1 + 1/3 p2
5612 and of course r0 = p0, r3 = p2
5615 int contour, point = 0, first_pt;
5616 FT_Outline *outline = &ft_face->glyph->outline;
5617 TTPOLYGONHEADER *pph;
5618 TTPOLYCURVE *ppc;
5619 DWORD pph_start, cpfx, type;
5620 FT_Vector cubic_control[4];
5621 if(buflen == 0) buf = NULL;
5623 if (needsTransform && buf) {
5624 pFT_Outline_Transform(outline, &transMat);
5627 for(contour = 0; contour < outline->n_contours; contour++) {
5628 pph_start = needed;
5629 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5630 first_pt = point;
5631 if(buf) {
5632 pph->dwType = TT_POLYGON_TYPE;
5633 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5635 needed += sizeof(*pph);
5636 point++;
5637 while(point <= outline->contours[contour]) {
5638 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5639 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5640 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5641 cpfx = 0;
5642 do {
5643 if(type == TT_PRIM_LINE) {
5644 if(buf)
5645 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5646 cpfx++;
5647 point++;
5648 } else {
5649 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5650 so cpfx = 3n */
5652 /* FIXME: Possible optimization in endpoint calculation
5653 if there are two consecutive curves */
5654 cubic_control[0] = outline->points[point-1];
5655 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5656 cubic_control[0].x += outline->points[point].x + 1;
5657 cubic_control[0].y += outline->points[point].y + 1;
5658 cubic_control[0].x >>= 1;
5659 cubic_control[0].y >>= 1;
5661 if(point+1 > outline->contours[contour])
5662 cubic_control[3] = outline->points[first_pt];
5663 else {
5664 cubic_control[3] = outline->points[point+1];
5665 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5666 cubic_control[3].x += outline->points[point].x + 1;
5667 cubic_control[3].y += outline->points[point].y + 1;
5668 cubic_control[3].x >>= 1;
5669 cubic_control[3].y >>= 1;
5672 /* r1 = 1/3 p0 + 2/3 p1
5673 r2 = 1/3 p2 + 2/3 p1 */
5674 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5675 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5676 cubic_control[2] = cubic_control[1];
5677 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5678 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5679 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5680 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5681 if(buf) {
5682 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5683 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5684 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5686 cpfx += 3;
5687 point++;
5689 } while(point <= outline->contours[contour] &&
5690 (outline->tags[point] & FT_Curve_Tag_On) ==
5691 (outline->tags[point-1] & FT_Curve_Tag_On));
5692 /* At the end of a contour Windows adds the start point,
5693 but only for Beziers and we've already done that.
5695 if(point <= outline->contours[contour] &&
5696 outline->tags[point] & FT_Curve_Tag_On) {
5697 /* This is the closing pt of a bezier, but we've already
5698 added it, so just inc point and carry on */
5699 point++;
5701 if(buf) {
5702 ppc->wType = type;
5703 ppc->cpfx = cpfx;
5705 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5707 if(buf)
5708 pph->cb = needed - pph_start;
5710 break;
5713 default:
5714 FIXME("Unsupported format %d\n", format);
5715 LeaveCriticalSection( &freetype_cs );
5716 return GDI_ERROR;
5718 LeaveCriticalSection( &freetype_cs );
5719 return needed;
5722 static BOOL get_bitmap_text_metrics(GdiFont *font)
5724 FT_Face ft_face = font->ft_face;
5725 #ifdef HAVE_FREETYPE_FTWINFNT_H
5726 FT_WinFNT_HeaderRec winfnt_header;
5727 #endif
5728 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5729 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5730 font->potm->otmSize = size;
5732 #define TM font->potm->otmTextMetrics
5733 #ifdef HAVE_FREETYPE_FTWINFNT_H
5734 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5736 TM.tmHeight = winfnt_header.pixel_height;
5737 TM.tmAscent = winfnt_header.ascent;
5738 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5739 TM.tmInternalLeading = winfnt_header.internal_leading;
5740 TM.tmExternalLeading = winfnt_header.external_leading;
5741 TM.tmAveCharWidth = winfnt_header.avg_width;
5742 TM.tmMaxCharWidth = winfnt_header.max_width;
5743 TM.tmWeight = winfnt_header.weight;
5744 TM.tmOverhang = 0;
5745 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5746 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5747 TM.tmFirstChar = winfnt_header.first_char;
5748 TM.tmLastChar = winfnt_header.last_char;
5749 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5750 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5751 TM.tmItalic = winfnt_header.italic;
5752 TM.tmUnderlined = font->underline;
5753 TM.tmStruckOut = font->strikeout;
5754 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5755 TM.tmCharSet = winfnt_header.charset;
5757 else
5758 #endif
5760 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5761 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5762 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5763 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5764 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5765 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5766 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5767 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5768 TM.tmOverhang = 0;
5769 TM.tmDigitizedAspectX = 96; /* FIXME */
5770 TM.tmDigitizedAspectY = 96; /* FIXME */
5771 TM.tmFirstChar = 1;
5772 TM.tmLastChar = 255;
5773 TM.tmDefaultChar = 32;
5774 TM.tmBreakChar = 32;
5775 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5776 TM.tmUnderlined = font->underline;
5777 TM.tmStruckOut = font->strikeout;
5778 /* NB inverted meaning of TMPF_FIXED_PITCH */
5779 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5780 TM.tmCharSet = font->charset;
5782 #undef TM
5784 return TRUE;
5788 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5790 double scale_x, scale_y;
5792 if (font->aveWidth)
5794 scale_x = (double)font->aveWidth;
5795 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5797 else
5798 scale_x = font->scale_y;
5800 scale_x *= fabs(font->font_desc.matrix.eM11);
5801 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5803 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5804 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5806 SCALE_Y(ptm->tmHeight);
5807 SCALE_Y(ptm->tmAscent);
5808 SCALE_Y(ptm->tmDescent);
5809 SCALE_Y(ptm->tmInternalLeading);
5810 SCALE_Y(ptm->tmExternalLeading);
5811 SCALE_Y(ptm->tmOverhang);
5813 SCALE_X(ptm->tmAveCharWidth);
5814 SCALE_X(ptm->tmMaxCharWidth);
5816 #undef SCALE_X
5817 #undef SCALE_Y
5820 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5822 double scale_x, scale_y;
5824 if (font->aveWidth)
5826 scale_x = (double)font->aveWidth;
5827 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5829 else
5830 scale_x = font->scale_y;
5832 scale_x *= fabs(font->font_desc.matrix.eM11);
5833 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5835 scale_font_metrics(font, &potm->otmTextMetrics);
5837 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5838 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5840 SCALE_Y(potm->otmAscent);
5841 SCALE_Y(potm->otmDescent);
5842 SCALE_Y(potm->otmLineGap);
5843 SCALE_Y(potm->otmsCapEmHeight);
5844 SCALE_Y(potm->otmsXHeight);
5845 SCALE_Y(potm->otmrcFontBox.top);
5846 SCALE_Y(potm->otmrcFontBox.bottom);
5847 SCALE_X(potm->otmrcFontBox.left);
5848 SCALE_X(potm->otmrcFontBox.right);
5849 SCALE_Y(potm->otmMacAscent);
5850 SCALE_Y(potm->otmMacDescent);
5851 SCALE_Y(potm->otmMacLineGap);
5852 SCALE_X(potm->otmptSubscriptSize.x);
5853 SCALE_Y(potm->otmptSubscriptSize.y);
5854 SCALE_X(potm->otmptSubscriptOffset.x);
5855 SCALE_Y(potm->otmptSubscriptOffset.y);
5856 SCALE_X(potm->otmptSuperscriptSize.x);
5857 SCALE_Y(potm->otmptSuperscriptSize.y);
5858 SCALE_X(potm->otmptSuperscriptOffset.x);
5859 SCALE_Y(potm->otmptSuperscriptOffset.y);
5860 SCALE_Y(potm->otmsStrikeoutSize);
5861 SCALE_Y(potm->otmsStrikeoutPosition);
5862 SCALE_Y(potm->otmsUnderscoreSize);
5863 SCALE_Y(potm->otmsUnderscorePosition);
5865 #undef SCALE_X
5866 #undef SCALE_Y
5869 /*************************************************************
5870 * WineEngGetTextMetrics
5873 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5875 GDI_CheckNotLock();
5876 EnterCriticalSection( &freetype_cs );
5877 if(!font->potm) {
5878 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5879 if(!get_bitmap_text_metrics(font))
5881 LeaveCriticalSection( &freetype_cs );
5882 return FALSE;
5885 /* Make sure that the font has sane width/height ratio */
5886 if (font->aveWidth)
5888 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5890 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5891 font->aveWidth = 0;
5896 *ptm = font->potm->otmTextMetrics;
5897 scale_font_metrics(font, ptm);
5898 LeaveCriticalSection( &freetype_cs );
5899 return TRUE;
5902 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5904 int i;
5906 for(i = 0; i < ft_face->num_charmaps; i++)
5908 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5909 return TRUE;
5911 return FALSE;
5914 /*************************************************************
5915 * WineEngGetOutlineTextMetrics
5918 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5919 OUTLINETEXTMETRICW *potm)
5921 FT_Face ft_face = font->ft_face;
5922 UINT needed, lenfam, lensty, ret;
5923 TT_OS2 *pOS2;
5924 TT_HoriHeader *pHori;
5925 TT_Postscript *pPost;
5926 FT_Fixed x_scale, y_scale;
5927 WCHAR *family_nameW, *style_nameW;
5928 static const WCHAR spaceW[] = {' ', '\0'};
5929 char *cp;
5930 INT ascent, descent;
5932 TRACE("font=%p\n", font);
5934 if(!FT_IS_SCALABLE(ft_face))
5935 return 0;
5937 GDI_CheckNotLock();
5938 EnterCriticalSection( &freetype_cs );
5940 if(font->potm) {
5941 if(cbSize >= font->potm->otmSize)
5943 memcpy(potm, font->potm, font->potm->otmSize);
5944 scale_outline_font_metrics(font, potm);
5946 LeaveCriticalSection( &freetype_cs );
5947 return font->potm->otmSize;
5951 needed = sizeof(*potm);
5953 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5954 family_nameW = strdupW(font->name);
5956 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5957 * sizeof(WCHAR);
5958 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5959 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5960 style_nameW, lensty/sizeof(WCHAR));
5962 /* These names should be read from the TT name table */
5964 /* length of otmpFamilyName */
5965 needed += lenfam;
5967 /* length of otmpFaceName */
5968 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5969 needed += lenfam; /* just the family name */
5970 } else {
5971 needed += lenfam + lensty; /* family + " " + style */
5974 /* length of otmpStyleName */
5975 needed += lensty;
5977 /* length of otmpFullName */
5978 needed += lenfam + lensty;
5981 x_scale = ft_face->size->metrics.x_scale;
5982 y_scale = ft_face->size->metrics.y_scale;
5984 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5985 if(!pOS2) {
5986 FIXME("Can't find OS/2 table - not TT font?\n");
5987 ret = 0;
5988 goto end;
5991 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5992 if(!pHori) {
5993 FIXME("Can't find HHEA table - not TT font?\n");
5994 ret = 0;
5995 goto end;
5998 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6000 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",
6001 pOS2->usWinAscent, pOS2->usWinDescent,
6002 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6003 ft_face->ascender, ft_face->descender, ft_face->height,
6004 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6005 ft_face->bbox.yMax, ft_face->bbox.yMin);
6007 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6008 font->potm->otmSize = needed;
6010 #define TM font->potm->otmTextMetrics
6012 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6013 ascent = pHori->Ascender;
6014 descent = -pHori->Descender;
6015 } else {
6016 ascent = pOS2->usWinAscent;
6017 descent = pOS2->usWinDescent;
6020 if(font->yMax) {
6021 TM.tmAscent = font->yMax;
6022 TM.tmDescent = -font->yMin;
6023 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6024 } else {
6025 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6026 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6027 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6028 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6031 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6033 /* MSDN says:
6034 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6036 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6037 ((ascent + descent) -
6038 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6040 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6041 if (TM.tmAveCharWidth == 0) {
6042 TM.tmAveCharWidth = 1;
6044 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6045 TM.tmWeight = FW_REGULAR;
6046 if (font->fake_bold)
6047 TM.tmWeight = FW_BOLD;
6048 else
6050 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6052 if (pOS2->usWeightClass > FW_MEDIUM)
6053 TM.tmWeight = pOS2->usWeightClass;
6055 else if (pOS2->usWeightClass <= FW_MEDIUM)
6056 TM.tmWeight = pOS2->usWeightClass;
6058 TM.tmOverhang = 0;
6059 TM.tmDigitizedAspectX = 300;
6060 TM.tmDigitizedAspectY = 300;
6061 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6062 * symbol range to 0 - f0ff
6065 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6067 TM.tmFirstChar = 0;
6068 switch(GetACP())
6070 case 1257: /* Baltic */
6071 TM.tmLastChar = 0xf8fd;
6072 break;
6073 default:
6074 TM.tmLastChar = 0xf0ff;
6076 TM.tmBreakChar = 0x20;
6077 TM.tmDefaultChar = 0x1f;
6079 else
6081 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6082 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6084 if(pOS2->usFirstCharIndex <= 1)
6085 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6086 else if (pOS2->usFirstCharIndex > 0xff)
6087 TM.tmBreakChar = 0x20;
6088 else
6089 TM.tmBreakChar = pOS2->usFirstCharIndex;
6090 TM.tmDefaultChar = TM.tmBreakChar - 1;
6092 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6093 TM.tmUnderlined = font->underline;
6094 TM.tmStruckOut = font->strikeout;
6096 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6097 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6098 (pOS2->version == 0xFFFFU ||
6099 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6100 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6101 else
6102 TM.tmPitchAndFamily = 0;
6104 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6106 case PAN_FAMILY_SCRIPT:
6107 TM.tmPitchAndFamily |= FF_SCRIPT;
6108 break;
6110 case PAN_FAMILY_DECORATIVE:
6111 TM.tmPitchAndFamily |= FF_DECORATIVE;
6112 break;
6114 case PAN_ANY:
6115 case PAN_NO_FIT:
6116 case PAN_FAMILY_TEXT_DISPLAY:
6117 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6118 /* which is clearly not what the panose spec says. */
6119 default:
6120 if(TM.tmPitchAndFamily == 0 || /* fixed */
6121 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6122 TM.tmPitchAndFamily = FF_MODERN;
6123 else
6125 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6127 case PAN_ANY:
6128 case PAN_NO_FIT:
6129 default:
6130 TM.tmPitchAndFamily |= FF_DONTCARE;
6131 break;
6133 case PAN_SERIF_COVE:
6134 case PAN_SERIF_OBTUSE_COVE:
6135 case PAN_SERIF_SQUARE_COVE:
6136 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6137 case PAN_SERIF_SQUARE:
6138 case PAN_SERIF_THIN:
6139 case PAN_SERIF_BONE:
6140 case PAN_SERIF_EXAGGERATED:
6141 case PAN_SERIF_TRIANGLE:
6142 TM.tmPitchAndFamily |= FF_ROMAN;
6143 break;
6145 case PAN_SERIF_NORMAL_SANS:
6146 case PAN_SERIF_OBTUSE_SANS:
6147 case PAN_SERIF_PERP_SANS:
6148 case PAN_SERIF_FLARED:
6149 case PAN_SERIF_ROUNDED:
6150 TM.tmPitchAndFamily |= FF_SWISS;
6151 break;
6154 break;
6157 if(FT_IS_SCALABLE(ft_face))
6158 TM.tmPitchAndFamily |= TMPF_VECTOR;
6160 if(FT_IS_SFNT(ft_face))
6162 if (font->ntmFlags & NTM_PS_OPENTYPE)
6163 TM.tmPitchAndFamily |= TMPF_DEVICE;
6164 else
6165 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6168 TM.tmCharSet = font->charset;
6170 font->potm->otmFiller = 0;
6171 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6172 font->potm->otmfsSelection = pOS2->fsSelection;
6173 font->potm->otmfsType = pOS2->fsType;
6174 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6175 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6176 font->potm->otmItalicAngle = 0; /* POST table */
6177 font->potm->otmEMSquare = ft_face->units_per_EM;
6178 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6179 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6180 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6181 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6182 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6183 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6184 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6185 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6186 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6187 font->potm->otmMacAscent = TM.tmAscent;
6188 font->potm->otmMacDescent = -TM.tmDescent;
6189 font->potm->otmMacLineGap = font->potm->otmLineGap;
6190 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6191 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6192 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6193 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6194 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6195 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6196 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6197 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6198 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6199 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6200 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6201 if(!pPost) {
6202 font->potm->otmsUnderscoreSize = 0;
6203 font->potm->otmsUnderscorePosition = 0;
6204 } else {
6205 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6206 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6208 #undef TM
6210 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6211 cp = (char*)font->potm + sizeof(*font->potm);
6212 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6213 strcpyW((WCHAR*)cp, family_nameW);
6214 cp += lenfam;
6215 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6216 strcpyW((WCHAR*)cp, style_nameW);
6217 cp += lensty;
6218 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6219 strcpyW((WCHAR*)cp, family_nameW);
6220 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6221 strcatW((WCHAR*)cp, spaceW);
6222 strcatW((WCHAR*)cp, style_nameW);
6223 cp += lenfam + lensty;
6224 } else
6225 cp += lenfam;
6226 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6227 strcpyW((WCHAR*)cp, family_nameW);
6228 strcatW((WCHAR*)cp, spaceW);
6229 strcatW((WCHAR*)cp, style_nameW);
6230 ret = needed;
6232 if(potm && needed <= cbSize)
6234 memcpy(potm, font->potm, font->potm->otmSize);
6235 scale_outline_font_metrics(font, potm);
6238 end:
6239 HeapFree(GetProcessHeap(), 0, style_nameW);
6240 HeapFree(GetProcessHeap(), 0, family_nameW);
6242 LeaveCriticalSection( &freetype_cs );
6243 return ret;
6246 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6248 HFONTLIST *hfontlist;
6249 child->font = alloc_font();
6250 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6251 if(!child->font->ft_face)
6253 free_font(child->font);
6254 child->font = NULL;
6255 return FALSE;
6258 child->font->font_desc = font->font_desc;
6259 child->font->ntmFlags = child->face->ntmFlags;
6260 child->font->orientation = font->orientation;
6261 child->font->scale_y = font->scale_y;
6262 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6263 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6264 child->font->name = strdupW(child->face->family->FamilyName);
6265 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6266 child->font->base_font = font;
6267 list_add_head(&child_font_list, &child->font->entry);
6268 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6269 return TRUE;
6272 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6274 FT_UInt g;
6275 CHILD_FONT *child_font;
6277 if(font->base_font)
6278 font = font->base_font;
6280 *linked_font = font;
6282 if((*glyph = get_glyph_index(font, c)))
6283 return TRUE;
6285 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6287 if(!child_font->font)
6288 if(!load_child_font(font, child_font))
6289 continue;
6291 if(!child_font->font->ft_face)
6292 continue;
6293 g = get_glyph_index(child_font->font, c);
6294 if(g)
6296 *glyph = g;
6297 *linked_font = child_font->font;
6298 return TRUE;
6301 return FALSE;
6304 /*************************************************************
6305 * WineEngGetCharWidth
6308 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6309 LPINT buffer)
6311 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6312 UINT c;
6313 GLYPHMETRICS gm;
6314 FT_UInt glyph_index;
6315 GdiFont *linked_font;
6317 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6319 GDI_CheckNotLock();
6320 EnterCriticalSection( &freetype_cs );
6321 for(c = firstChar; c <= lastChar; c++) {
6322 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6323 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6324 &gm, 0, NULL, &identity);
6325 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6327 LeaveCriticalSection( &freetype_cs );
6328 return TRUE;
6331 /*************************************************************
6332 * WineEngGetCharABCWidths
6335 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6336 LPABC buffer)
6338 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6339 UINT c;
6340 GLYPHMETRICS gm;
6341 FT_UInt glyph_index;
6342 GdiFont *linked_font;
6344 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6346 if(!FT_IS_SCALABLE(font->ft_face))
6347 return FALSE;
6349 GDI_CheckNotLock();
6350 EnterCriticalSection( &freetype_cs );
6352 for(c = firstChar; c <= lastChar; c++) {
6353 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6354 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6355 &gm, 0, NULL, &identity);
6356 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6357 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6358 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6359 FONT_GM(linked_font,glyph_index)->bbx;
6361 LeaveCriticalSection( &freetype_cs );
6362 return TRUE;
6365 /*************************************************************
6366 * WineEngGetCharABCWidthsFloat
6369 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6371 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6372 UINT c;
6373 GLYPHMETRICS gm;
6374 FT_UInt glyph_index;
6375 GdiFont *linked_font;
6377 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6379 GDI_CheckNotLock();
6380 EnterCriticalSection( &freetype_cs );
6382 for (c = first; c <= last; c++)
6384 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6385 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6386 &gm, 0, NULL, &identity);
6387 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6388 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6389 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6390 FONT_GM(linked_font, glyph_index)->lsb -
6391 FONT_GM(linked_font, glyph_index)->bbx;
6393 LeaveCriticalSection( &freetype_cs );
6394 return TRUE;
6397 /*************************************************************
6398 * WineEngGetCharABCWidthsI
6401 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6402 LPABC buffer)
6404 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6405 UINT c;
6406 GLYPHMETRICS gm;
6407 FT_UInt glyph_index;
6408 GdiFont *linked_font;
6410 if(!FT_HAS_HORIZONTAL(font->ft_face))
6411 return FALSE;
6413 GDI_CheckNotLock();
6414 EnterCriticalSection( &freetype_cs );
6416 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6417 if (!pgi)
6418 for(c = firstChar; c < firstChar+count; c++) {
6419 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6420 &gm, 0, NULL, &identity);
6421 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6422 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6423 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6424 - FONT_GM(linked_font,c)->bbx;
6426 else
6427 for(c = 0; c < count; c++) {
6428 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6429 &gm, 0, NULL, &identity);
6430 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6431 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6432 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6433 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6436 LeaveCriticalSection( &freetype_cs );
6437 return TRUE;
6440 /*************************************************************
6441 * WineEngGetTextExtentExPoint
6444 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6445 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6447 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6448 INT idx;
6449 INT nfit = 0, ext;
6450 GLYPHMETRICS gm;
6451 TEXTMETRICW tm;
6452 FT_UInt glyph_index;
6453 GdiFont *linked_font;
6455 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6456 max_ext, size);
6458 GDI_CheckNotLock();
6459 EnterCriticalSection( &freetype_cs );
6461 size->cx = 0;
6462 WineEngGetTextMetrics(font, &tm);
6463 size->cy = tm.tmHeight;
6465 for(idx = 0; idx < count; idx++) {
6466 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6467 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6468 &gm, 0, NULL, &identity);
6469 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6470 ext = size->cx;
6471 if (! pnfit || ext <= max_ext) {
6472 ++nfit;
6473 if (dxs)
6474 dxs[idx] = ext;
6478 if (pnfit)
6479 *pnfit = nfit;
6481 LeaveCriticalSection( &freetype_cs );
6482 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6483 return TRUE;
6486 /*************************************************************
6487 * WineEngGetTextExtentExPointI
6490 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6491 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6493 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6494 INT idx;
6495 INT nfit = 0, ext;
6496 GLYPHMETRICS gm;
6497 TEXTMETRICW tm;
6499 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6501 GDI_CheckNotLock();
6502 EnterCriticalSection( &freetype_cs );
6504 size->cx = 0;
6505 WineEngGetTextMetrics(font, &tm);
6506 size->cy = tm.tmHeight;
6508 for(idx = 0; idx < count; idx++) {
6509 WineEngGetGlyphOutline(font, indices[idx],
6510 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6511 &identity);
6512 size->cx += FONT_GM(font,indices[idx])->adv;
6513 ext = size->cx;
6514 if (! pnfit || ext <= max_ext) {
6515 ++nfit;
6516 if (dxs)
6517 dxs[idx] = ext;
6521 if (pnfit)
6522 *pnfit = nfit;
6524 LeaveCriticalSection( &freetype_cs );
6525 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6526 return TRUE;
6529 /*************************************************************
6530 * WineEngGetFontData
6533 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6534 DWORD cbData)
6536 FT_Face ft_face = font->ft_face;
6537 FT_ULong len;
6538 FT_Error err;
6540 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6541 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6542 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6544 if(!FT_IS_SFNT(ft_face))
6545 return GDI_ERROR;
6547 if(!buf)
6548 len = 0;
6549 else
6550 len = cbData;
6552 if(table) { /* MS tags differ in endianness from FT ones */
6553 table = table >> 24 | table << 24 |
6554 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6557 /* make sure value of len is the value freetype says it needs */
6558 if(buf && len)
6560 FT_ULong needed = 0;
6561 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6562 if( !err && needed < len) len = needed;
6564 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6566 if(err) {
6567 TRACE("Can't find table %c%c%c%c\n",
6568 /* bytes were reversed */
6569 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6570 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6571 return GDI_ERROR;
6573 return len;
6576 /*************************************************************
6577 * WineEngGetTextFace
6580 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6582 INT n = strlenW(font->name) + 1;
6583 if(str) {
6584 lstrcpynW(str, font->name, count);
6585 return min(count, n);
6586 } else
6587 return n;
6590 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6592 if (fs) *fs = font->fs;
6593 return font->charset;
6596 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6598 GdiFont *font = dc->gdiFont, *linked_font;
6599 struct list *first_hfont;
6600 BOOL ret;
6602 GDI_CheckNotLock();
6603 EnterCriticalSection( &freetype_cs );
6604 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6605 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6606 if(font == linked_font)
6607 *new_hfont = dc->hFont;
6608 else
6610 first_hfont = list_head(&linked_font->hfontlist);
6611 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6613 LeaveCriticalSection( &freetype_cs );
6614 return ret;
6617 /* Retrieve a list of supported Unicode ranges for a given font.
6618 * Can be called with NULL gs to calculate the buffer size. Returns
6619 * the number of ranges found.
6621 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6623 DWORD num_ranges = 0;
6625 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6627 FT_UInt glyph_code;
6628 FT_ULong char_code, char_code_prev;
6630 glyph_code = 0;
6631 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6633 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6634 face->num_glyphs, glyph_code, char_code);
6636 if (!glyph_code) return 0;
6638 if (gs)
6640 gs->ranges[0].wcLow = (USHORT)char_code;
6641 gs->ranges[0].cGlyphs = 0;
6642 gs->cGlyphsSupported = 0;
6645 num_ranges = 1;
6646 while (glyph_code)
6648 if (char_code < char_code_prev)
6650 ERR("expected increasing char code from FT_Get_Next_Char\n");
6651 return 0;
6653 if (char_code - char_code_prev > 1)
6655 num_ranges++;
6656 if (gs)
6658 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6659 gs->ranges[num_ranges - 1].cGlyphs = 1;
6660 gs->cGlyphsSupported++;
6663 else if (gs)
6665 gs->ranges[num_ranges - 1].cGlyphs++;
6666 gs->cGlyphsSupported++;
6668 char_code_prev = char_code;
6669 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6672 else
6673 FIXME("encoding %u not supported\n", face->charmap->encoding);
6675 return num_ranges;
6678 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6680 DWORD size = 0;
6681 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6683 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6684 if (glyphset)
6686 glyphset->cbThis = size;
6687 glyphset->cRanges = num_ranges;
6688 glyphset->flAccel = 0;
6690 return size;
6693 /*************************************************************
6694 * FontIsLinked
6696 BOOL WineEngFontIsLinked(GdiFont *font)
6698 BOOL ret;
6699 GDI_CheckNotLock();
6700 EnterCriticalSection( &freetype_cs );
6701 ret = !list_empty(&font->child_fonts);
6702 LeaveCriticalSection( &freetype_cs );
6703 return ret;
6706 static BOOL is_hinting_enabled(void)
6708 /* Use the >= 2.2.0 function if available */
6709 if(pFT_Get_TrueType_Engine_Type)
6711 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6712 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6714 #ifdef FT_DRIVER_HAS_HINTER
6715 else
6717 FT_Module mod;
6719 /* otherwise if we've been compiled with < 2.2.0 headers
6720 use the internal macro */
6721 mod = pFT_Get_Module(library, "truetype");
6722 if(mod && FT_DRIVER_HAS_HINTER(mod))
6723 return TRUE;
6725 #endif
6727 return FALSE;
6730 static BOOL is_subpixel_rendering_enabled( void )
6732 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6733 return pFT_Library_SetLcdFilter &&
6734 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6735 #else
6736 return FALSE;
6737 #endif
6740 /*************************************************************************
6741 * GetRasterizerCaps (GDI32.@)
6743 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6745 static int hinting = -1;
6746 static int subpixel = -1;
6748 if(hinting == -1)
6750 hinting = is_hinting_enabled();
6751 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6754 if ( subpixel == -1 )
6756 subpixel = is_subpixel_rendering_enabled();
6757 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6760 lprs->nSize = sizeof(RASTERIZER_STATUS);
6761 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6762 if ( subpixel )
6763 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6764 lprs->nLanguageID = 0;
6765 return TRUE;
6768 /*************************************************************
6769 * WineEngRealizationInfo
6771 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6773 FIXME("(%p, %p): stub!\n", font, info);
6775 info->flags = 1;
6776 if(FT_IS_SCALABLE(font->ft_face))
6777 info->flags |= 2;
6779 info->cache_num = font->cache_num;
6780 info->unknown2 = -1;
6781 return TRUE;
6784 /*************************************************************************
6785 * Kerning support for TrueType fonts
6787 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6789 struct TT_kern_table
6791 USHORT version;
6792 USHORT nTables;
6795 struct TT_kern_subtable
6797 USHORT version;
6798 USHORT length;
6799 union
6801 USHORT word;
6802 struct
6804 USHORT horizontal : 1;
6805 USHORT minimum : 1;
6806 USHORT cross_stream: 1;
6807 USHORT override : 1;
6808 USHORT reserved1 : 4;
6809 USHORT format : 8;
6810 } bits;
6811 } coverage;
6814 struct TT_format0_kern_subtable
6816 USHORT nPairs;
6817 USHORT searchRange;
6818 USHORT entrySelector;
6819 USHORT rangeShift;
6822 struct TT_kern_pair
6824 USHORT left;
6825 USHORT right;
6826 short value;
6829 static DWORD parse_format0_kern_subtable(GdiFont *font,
6830 const struct TT_format0_kern_subtable *tt_f0_ks,
6831 const USHORT *glyph_to_char,
6832 KERNINGPAIR *kern_pair, DWORD cPairs)
6834 USHORT i, nPairs;
6835 const struct TT_kern_pair *tt_kern_pair;
6837 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6839 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6841 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6842 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6843 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6845 if (!kern_pair || !cPairs)
6846 return nPairs;
6848 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6850 nPairs = min(nPairs, cPairs);
6852 for (i = 0; i < nPairs; i++)
6854 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6855 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6856 /* this algorithm appears to better match what Windows does */
6857 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6858 if (kern_pair->iKernAmount < 0)
6860 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6861 kern_pair->iKernAmount -= font->ppem;
6863 else if (kern_pair->iKernAmount > 0)
6865 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6866 kern_pair->iKernAmount += font->ppem;
6868 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6870 TRACE("left %u right %u value %d\n",
6871 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6873 kern_pair++;
6875 TRACE("copied %u entries\n", nPairs);
6876 return nPairs;
6879 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6881 DWORD length;
6882 void *buf;
6883 const struct TT_kern_table *tt_kern_table;
6884 const struct TT_kern_subtable *tt_kern_subtable;
6885 USHORT i, nTables;
6886 USHORT *glyph_to_char;
6888 GDI_CheckNotLock();
6889 EnterCriticalSection( &freetype_cs );
6890 if (font->total_kern_pairs != (DWORD)-1)
6892 if (cPairs && kern_pair)
6894 cPairs = min(cPairs, font->total_kern_pairs);
6895 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6896 LeaveCriticalSection( &freetype_cs );
6897 return cPairs;
6899 LeaveCriticalSection( &freetype_cs );
6900 return font->total_kern_pairs;
6903 font->total_kern_pairs = 0;
6905 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6907 if (length == GDI_ERROR)
6909 TRACE("no kerning data in the font\n");
6910 LeaveCriticalSection( &freetype_cs );
6911 return 0;
6914 buf = HeapAlloc(GetProcessHeap(), 0, length);
6915 if (!buf)
6917 WARN("Out of memory\n");
6918 LeaveCriticalSection( &freetype_cs );
6919 return 0;
6922 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6924 /* build a glyph index to char code map */
6925 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6926 if (!glyph_to_char)
6928 WARN("Out of memory allocating a glyph index to char code map\n");
6929 HeapFree(GetProcessHeap(), 0, buf);
6930 LeaveCriticalSection( &freetype_cs );
6931 return 0;
6934 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6936 FT_UInt glyph_code;
6937 FT_ULong char_code;
6939 glyph_code = 0;
6940 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6942 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6943 font->ft_face->num_glyphs, glyph_code, char_code);
6945 while (glyph_code)
6947 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6949 /* FIXME: This doesn't match what Windows does: it does some fancy
6950 * things with duplicate glyph index to char code mappings, while
6951 * we just avoid overriding existing entries.
6953 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6954 glyph_to_char[glyph_code] = (USHORT)char_code;
6956 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6959 else
6961 ULONG n;
6963 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6964 for (n = 0; n <= 65535; n++)
6965 glyph_to_char[n] = (USHORT)n;
6968 tt_kern_table = buf;
6969 nTables = GET_BE_WORD(tt_kern_table->nTables);
6970 TRACE("version %u, nTables %u\n",
6971 GET_BE_WORD(tt_kern_table->version), nTables);
6973 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6975 for (i = 0; i < nTables; i++)
6977 struct TT_kern_subtable tt_kern_subtable_copy;
6979 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6980 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6981 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6983 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6984 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6985 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6987 /* According to the TrueType specification this is the only format
6988 * that will be properly interpreted by Windows and OS/2
6990 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6992 DWORD new_chunk, old_total = font->total_kern_pairs;
6994 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6995 glyph_to_char, NULL, 0);
6996 font->total_kern_pairs += new_chunk;
6998 if (!font->kern_pairs)
6999 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7000 font->total_kern_pairs * sizeof(*font->kern_pairs));
7001 else
7002 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7003 font->total_kern_pairs * sizeof(*font->kern_pairs));
7005 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7006 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7008 else
7009 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7011 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7014 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7015 HeapFree(GetProcessHeap(), 0, buf);
7017 if (cPairs && kern_pair)
7019 cPairs = min(cPairs, font->total_kern_pairs);
7020 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7021 LeaveCriticalSection( &freetype_cs );
7022 return cPairs;
7024 LeaveCriticalSection( &freetype_cs );
7025 return font->total_kern_pairs;
7028 #else /* HAVE_FREETYPE */
7030 /*************************************************************************/
7032 BOOL WineEngInit(void)
7034 return FALSE;
7036 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
7038 return NULL;
7040 BOOL WineEngDestroyFontInstance(HFONT hfont)
7042 return FALSE;
7045 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
7047 return 1;
7050 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
7051 LPWORD pgi, DWORD flags)
7053 return GDI_ERROR;
7056 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
7057 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
7058 const MAT2* lpmat)
7060 ERR("called but we don't have FreeType\n");
7061 return GDI_ERROR;
7064 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
7066 ERR("called but we don't have FreeType\n");
7067 return FALSE;
7070 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
7071 OUTLINETEXTMETRICW *potm)
7073 ERR("called but we don't have FreeType\n");
7074 return 0;
7077 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
7078 LPINT buffer)
7080 ERR("called but we don't have FreeType\n");
7081 return FALSE;
7084 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
7085 LPABC buffer)
7087 ERR("called but we don't have FreeType\n");
7088 return FALSE;
7091 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
7093 ERR("called but we don't have FreeType\n");
7094 return FALSE;
7097 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
7098 LPABC buffer)
7100 ERR("called but we don't have FreeType\n");
7101 return FALSE;
7104 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
7105 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7107 ERR("called but we don't have FreeType\n");
7108 return FALSE;
7111 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
7112 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7114 ERR("called but we don't have FreeType\n");
7115 return FALSE;
7118 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
7119 DWORD cbData)
7121 ERR("called but we don't have FreeType\n");
7122 return GDI_ERROR;
7125 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
7127 ERR("called but we don't have FreeType\n");
7128 return 0;
7131 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7133 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7134 return 1;
7137 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7139 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7140 return TRUE;
7143 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7145 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7146 return NULL;
7149 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
7151 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
7152 return DEFAULT_CHARSET;
7155 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7157 return FALSE;
7160 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
7162 FIXME("(%p, %p): stub\n", font, glyphset);
7163 return 0;
7166 BOOL WineEngFontIsLinked(GdiFont *font)
7168 return FALSE;
7171 /*************************************************************************
7172 * GetRasterizerCaps (GDI32.@)
7174 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7176 lprs->nSize = sizeof(RASTERIZER_STATUS);
7177 lprs->wFlags = 0;
7178 lprs->nLanguageID = 0;
7179 return TRUE;
7182 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
7184 ERR("called but we don't have FreeType\n");
7185 return 0;
7188 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
7190 ERR("called but we don't have FreeType\n");
7191 return FALSE;
7194 #endif /* HAVE_FREETYPE */