gdi32: Keep track of the english family name if there's a localised name as well.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobae8ca4113b21535ed82eb03573ed642939fa3294
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 struct font_mapping
477 struct list entry;
478 int refcount;
479 dev_t dev;
480 ino_t ino;
481 void *data;
482 size_t size;
485 static struct list mappings_list = LIST_INIT( mappings_list );
487 static CRITICAL_SECTION freetype_cs;
488 static CRITICAL_SECTION_DEBUG critsect_debug =
490 0, 0, &freetype_cs,
491 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
492 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
494 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
496 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
498 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
499 static BOOL use_default_fallback = FALSE;
501 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
503 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
504 'W','i','n','d','o','w','s',' ','N','T','\\',
505 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
506 'S','y','s','t','e','m','L','i','n','k',0};
508 /****************************************
509 * Notes on .fon files
511 * The fonts System, FixedSys and Terminal are special. There are typically multiple
512 * versions installed for different resolutions and codepages. Windows stores which one to use
513 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
514 * Key Meaning
515 * FIXEDFON.FON FixedSys
516 * FONTS.FON System
517 * OEMFONT.FON Terminal
518 * LogPixels Current dpi set by the display control panel applet
519 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
520 * also has a LogPixels value that appears to mirror this)
522 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
523 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
524 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
525 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
526 * so that makes sense.
528 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
529 * to be mapped into the registry on Windows 2000 at least).
530 * I have
531 * woafont=app850.fon
532 * ega80woa.fon=ega80850.fon
533 * ega40woa.fon=ega40850.fon
534 * cga80woa.fon=cga80850.fon
535 * cga40woa.fon=cga40850.fon
538 /* These are all structures needed for the GSUB table */
540 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
541 #define TATEGAKI_LOWER_BOUND 0x02F1
543 typedef struct {
544 DWORD version;
545 WORD ScriptList;
546 WORD FeatureList;
547 WORD LookupList;
548 } GSUB_Header;
550 typedef struct {
551 CHAR ScriptTag[4];
552 WORD Script;
553 } GSUB_ScriptRecord;
555 typedef struct {
556 WORD ScriptCount;
557 GSUB_ScriptRecord ScriptRecord[1];
558 } GSUB_ScriptList;
560 typedef struct {
561 CHAR LangSysTag[4];
562 WORD LangSys;
563 } GSUB_LangSysRecord;
565 typedef struct {
566 WORD DefaultLangSys;
567 WORD LangSysCount;
568 GSUB_LangSysRecord LangSysRecord[1];
569 } GSUB_Script;
571 typedef struct {
572 WORD LookupOrder; /* Reserved */
573 WORD ReqFeatureIndex;
574 WORD FeatureCount;
575 WORD FeatureIndex[1];
576 } GSUB_LangSys;
578 typedef struct {
579 CHAR FeatureTag[4];
580 WORD Feature;
581 } GSUB_FeatureRecord;
583 typedef struct {
584 WORD FeatureCount;
585 GSUB_FeatureRecord FeatureRecord[1];
586 } GSUB_FeatureList;
588 typedef struct {
589 WORD FeatureParams; /* Reserved */
590 WORD LookupCount;
591 WORD LookupListIndex[1];
592 } GSUB_Feature;
594 typedef struct {
595 WORD LookupCount;
596 WORD Lookup[1];
597 } GSUB_LookupList;
599 typedef struct {
600 WORD LookupType;
601 WORD LookupFlag;
602 WORD SubTableCount;
603 WORD SubTable[1];
604 } GSUB_LookupTable;
606 typedef struct {
607 WORD CoverageFormat;
608 WORD GlyphCount;
609 WORD GlyphArray[1];
610 } GSUB_CoverageFormat1;
612 typedef struct {
613 WORD Start;
614 WORD End;
615 WORD StartCoverageIndex;
616 } GSUB_RangeRecord;
618 typedef struct {
619 WORD CoverageFormat;
620 WORD RangeCount;
621 GSUB_RangeRecord RangeRecord[1];
622 } GSUB_CoverageFormat2;
624 typedef struct {
625 WORD SubstFormat; /* = 1 */
626 WORD Coverage;
627 WORD DeltaGlyphID;
628 } GSUB_SingleSubstFormat1;
630 typedef struct {
631 WORD SubstFormat; /* = 2 */
632 WORD Coverage;
633 WORD GlyphCount;
634 WORD Substitute[1];
635 }GSUB_SingleSubstFormat2;
637 #ifdef HAVE_CARBON_CARBON_H
638 static char *find_cache_dir(void)
640 FSRef ref;
641 OSErr err;
642 static char cached_path[MAX_PATH];
643 static const char *wine = "/Wine", *fonts = "/Fonts";
645 if(*cached_path) return cached_path;
647 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
648 if(err != noErr)
650 WARN("can't create cached data folder\n");
651 return NULL;
653 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
654 if(err != noErr)
656 WARN("can't create cached data path\n");
657 *cached_path = '\0';
658 return NULL;
660 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
662 ERR("Could not create full path\n");
663 *cached_path = '\0';
664 return NULL;
666 strcat(cached_path, wine);
668 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
670 WARN("Couldn't mkdir %s\n", cached_path);
671 *cached_path = '\0';
672 return NULL;
674 strcat(cached_path, fonts);
675 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
677 WARN("Couldn't mkdir %s\n", cached_path);
678 *cached_path = '\0';
679 return NULL;
681 return cached_path;
684 /******************************************************************
685 * expand_mac_font
687 * Extracts individual TrueType font files from a Mac suitcase font
688 * and saves them into the user's caches directory (see
689 * find_cache_dir()).
690 * Returns a NULL terminated array of filenames.
692 * We do this because they are apps that try to read ttf files
693 * themselves and they don't like Mac suitcase files.
695 static char **expand_mac_font(const char *path)
697 FSRef ref;
698 SInt16 res_ref;
699 OSStatus s;
700 unsigned int idx;
701 const char *out_dir;
702 const char *filename;
703 int output_len;
704 struct {
705 char **array;
706 unsigned int size, max_size;
707 } ret;
709 TRACE("path %s\n", path);
711 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
712 if(s != noErr)
714 WARN("failed to get ref\n");
715 return NULL;
718 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
719 if(s != noErr)
721 TRACE("no data fork, so trying resource fork\n");
722 res_ref = FSOpenResFile(&ref, fsRdPerm);
723 if(res_ref == -1)
725 TRACE("unable to open resource fork\n");
726 return NULL;
730 ret.size = 0;
731 ret.max_size = 10;
732 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
733 if(!ret.array)
735 CloseResFile(res_ref);
736 return NULL;
739 out_dir = find_cache_dir();
741 filename = strrchr(path, '/');
742 if(!filename) filename = path;
743 else filename++;
745 /* output filename has the form out_dir/filename_%04x.ttf */
746 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
748 UseResFile(res_ref);
749 idx = 1;
750 while(1)
752 FamRec *fam_rec;
753 unsigned short *num_faces_ptr, num_faces, face;
754 AsscEntry *assoc;
755 Handle fond;
756 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
758 fond = Get1IndResource(fond_res, idx);
759 if(!fond) break;
760 TRACE("got fond resource %d\n", idx);
761 HLock(fond);
763 fam_rec = *(FamRec**)fond;
764 num_faces_ptr = (unsigned short *)(fam_rec + 1);
765 num_faces = GET_BE_WORD(*num_faces_ptr);
766 num_faces++;
767 assoc = (AsscEntry*)(num_faces_ptr + 1);
768 TRACE("num faces %04x\n", num_faces);
769 for(face = 0; face < num_faces; face++, assoc++)
771 Handle sfnt;
772 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
773 unsigned short size, font_id;
774 char *output;
776 size = GET_BE_WORD(assoc->fontSize);
777 font_id = GET_BE_WORD(assoc->fontID);
778 if(size != 0)
780 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
781 continue;
784 TRACE("trying to load sfnt id %04x\n", font_id);
785 sfnt = GetResource(sfnt_res, font_id);
786 if(!sfnt)
788 TRACE("can't get sfnt resource %04x\n", font_id);
789 continue;
792 output = HeapAlloc(GetProcessHeap(), 0, output_len);
793 if(output)
795 int fd;
797 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
799 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
800 if(fd != -1 || errno == EEXIST)
802 if(fd != -1)
804 unsigned char *sfnt_data;
806 HLock(sfnt);
807 sfnt_data = *(unsigned char**)sfnt;
808 write(fd, sfnt_data, GetHandleSize(sfnt));
809 HUnlock(sfnt);
810 close(fd);
812 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
814 ret.max_size *= 2;
815 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
817 ret.array[ret.size++] = output;
819 else
821 WARN("unable to create %s\n", output);
822 HeapFree(GetProcessHeap(), 0, output);
825 ReleaseResource(sfnt);
827 HUnlock(fond);
828 ReleaseResource(fond);
829 idx++;
831 CloseResFile(res_ref);
833 return ret.array;
836 #endif /* HAVE_CARBON_CARBON_H */
838 static inline BOOL is_win9x(void)
840 return GetVersion() & 0x80000000;
843 This function builds an FT_Fixed from a double. It fails if the absolute
844 value of the float number is greater than 32768.
846 static inline FT_Fixed FT_FixedFromFloat(double f)
848 return f * 0x10000;
852 This function builds an FT_Fixed from a FIXED. It simply put f.value
853 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
855 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
857 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
861 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
863 Family *family;
864 Face *face;
865 const char *file;
866 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
867 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
869 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
870 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
872 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
874 if(face_name && strcmpiW(face_name, family->FamilyName))
875 continue;
876 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
878 if (!face->file)
879 continue;
880 file = strrchr(face->file, '/');
881 if(!file)
882 file = face->file;
883 else
884 file++;
885 if(!strcasecmp(file, file_nameA))
887 HeapFree(GetProcessHeap(), 0, file_nameA);
888 return face;
892 HeapFree(GetProcessHeap(), 0, file_nameA);
893 return NULL;
896 static Family *find_family_from_name(const WCHAR *name)
898 Family *family;
900 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
902 if(!strcmpiW(family->FamilyName, name))
903 return family;
906 return NULL;
909 static void DumpSubstList(void)
911 FontSubst *psub;
913 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
915 if(psub->from.charset != -1 || psub->to.charset != -1)
916 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
917 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
918 else
919 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
920 debugstr_w(psub->to.name));
922 return;
925 static LPWSTR strdupW(LPCWSTR p)
927 LPWSTR ret;
928 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
929 ret = HeapAlloc(GetProcessHeap(), 0, len);
930 memcpy(ret, p, len);
931 return ret;
934 static LPSTR strdupA(LPCSTR p)
936 LPSTR ret;
937 DWORD len = (strlen(p) + 1);
938 ret = HeapAlloc(GetProcessHeap(), 0, len);
939 memcpy(ret, p, len);
940 return ret;
943 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
944 INT from_charset)
946 FontSubst *element;
948 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
950 if(!strcmpiW(element->from.name, from_name) &&
951 (element->from.charset == from_charset ||
952 element->from.charset == -1))
953 return element;
956 return NULL;
959 #define ADD_FONT_SUBST_FORCE 1
961 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
963 FontSubst *from_exist, *to_exist;
965 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
967 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
969 list_remove(&from_exist->entry);
970 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
971 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
972 HeapFree(GetProcessHeap(), 0, from_exist);
973 from_exist = NULL;
976 if(!from_exist)
978 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
980 if(to_exist)
982 HeapFree(GetProcessHeap(), 0, subst->to.name);
983 subst->to.name = strdupW(to_exist->to.name);
986 list_add_tail(subst_list, &subst->entry);
988 return TRUE;
991 HeapFree(GetProcessHeap(), 0, subst->from.name);
992 HeapFree(GetProcessHeap(), 0, subst->to.name);
993 HeapFree(GetProcessHeap(), 0, subst);
994 return FALSE;
997 static void split_subst_info(NameCs *nc, LPSTR str)
999 CHAR *p = strrchr(str, ',');
1000 DWORD len;
1002 nc->charset = -1;
1003 if(p && *(p+1)) {
1004 nc->charset = strtol(p+1, NULL, 10);
1005 *p = '\0';
1007 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1008 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1009 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1012 static void LoadSubstList(void)
1014 FontSubst *psub;
1015 HKEY hkey;
1016 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1017 LPSTR value;
1018 LPVOID data;
1020 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1021 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1022 &hkey) == ERROR_SUCCESS) {
1024 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1025 &valuelen, &datalen, NULL, NULL);
1027 valuelen++; /* returned value doesn't include room for '\0' */
1028 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1029 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1031 dlen = datalen;
1032 vlen = valuelen;
1033 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1034 &dlen) == ERROR_SUCCESS) {
1035 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1037 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1038 split_subst_info(&psub->from, value);
1039 split_subst_info(&psub->to, data);
1041 /* Win 2000 doesn't allow mapping between different charsets
1042 or mapping of DEFAULT_CHARSET */
1043 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1044 psub->to.charset == DEFAULT_CHARSET) {
1045 HeapFree(GetProcessHeap(), 0, psub->to.name);
1046 HeapFree(GetProcessHeap(), 0, psub->from.name);
1047 HeapFree(GetProcessHeap(), 0, psub);
1048 } else {
1049 add_font_subst(&font_subst_list, psub, 0);
1051 /* reset dlen and vlen */
1052 dlen = datalen;
1053 vlen = valuelen;
1055 HeapFree(GetProcessHeap(), 0, data);
1056 HeapFree(GetProcessHeap(), 0, value);
1057 RegCloseKey(hkey);
1062 /*****************************************************************
1063 * get_name_table_entry
1065 * Supply the platform, encoding, language and name ids in req
1066 * and if the name exists the function will fill in the string
1067 * and string_len members. The string is owned by FreeType so
1068 * don't free it. Returns TRUE if the name is found else FALSE.
1070 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1072 FT_SfntName name;
1073 FT_UInt num_names, name_index;
1075 if(FT_IS_SFNT(ft_face))
1077 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1079 for(name_index = 0; name_index < num_names; name_index++)
1081 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1083 if((name.platform_id == req->platform_id) &&
1084 (name.encoding_id == req->encoding_id) &&
1085 (name.language_id == req->language_id) &&
1086 (name.name_id == req->name_id))
1088 req->string = name.string;
1089 req->string_len = name.string_len;
1090 return TRUE;
1095 req->string = NULL;
1096 req->string_len = 0;
1097 return FALSE;
1100 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1102 WCHAR *ret = NULL;
1103 FT_SfntName name;
1105 name.platform_id = TT_PLATFORM_MICROSOFT;
1106 name.encoding_id = TT_MS_ID_UNICODE_CS;
1107 name.language_id = language_id;
1108 name.name_id = name_id;
1110 if(get_name_table_entry(ft_face, &name))
1112 FT_UInt i;
1114 /* String is not nul terminated and string_len is a byte length. */
1115 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1116 for(i = 0; i < name.string_len / 2; i++)
1118 WORD *tmp = (WORD *)&name.string[i * 2];
1119 ret[i] = GET_BE_WORD(*tmp);
1121 ret[i] = 0;
1122 TRACE("Got localised name %s\n", debugstr_w(ret));
1125 return ret;
1129 /*****************************************************************
1130 * load_sfnt_table
1132 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1133 * of FreeType that don't export this function.
1136 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1139 FT_Error err;
1141 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1142 if(pFT_Load_Sfnt_Table)
1144 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1146 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1147 else /* Do it the hard way */
1149 TT_Face tt_face = (TT_Face) ft_face;
1150 SFNT_Interface *sfnt;
1151 if (FT_Version.major==2 && FT_Version.minor==0)
1153 /* 2.0.x */
1154 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1156 else
1158 /* A field was added in the middle of the structure in 2.1.x */
1159 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1161 err = sfnt->load_any(tt_face, table, offset, buf, len);
1163 #else
1164 else
1166 static int msg;
1167 if(!msg)
1169 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1170 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1171 "Please upgrade your freetype library.\n");
1172 msg++;
1174 err = FT_Err_Unimplemented_Feature;
1176 #endif
1177 return err;
1180 static inline int TestStyles(DWORD flags, DWORD styles)
1182 return (flags & styles) == styles;
1185 static int StyleOrdering(Face *face)
1187 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1188 return 3;
1189 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1190 return 2;
1191 if (TestStyles(face->ntmFlags, NTM_BOLD))
1192 return 1;
1193 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1194 return 0;
1196 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1197 debugstr_w(face->family->FamilyName),
1198 debugstr_w(face->StyleName),
1199 face->ntmFlags);
1201 return 9999;
1204 /* Add a style of face to a font family using an ordering of the list such
1205 that regular fonts come before bold and italic, and single styles come
1206 before compound styles. */
1207 static void AddFaceToFamily(Face *face, Family *family)
1209 struct list *entry;
1211 LIST_FOR_EACH( entry, &family->faces )
1213 Face *ent = LIST_ENTRY(entry, Face, entry);
1214 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1216 list_add_before( entry, &face->entry );
1219 #define ADDFONT_EXTERNAL_FONT 0x01
1220 #define ADDFONT_FORCE_BITMAP 0x02
1221 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1223 FT_Face ft_face;
1224 TT_OS2 *pOS2;
1225 TT_Header *pHeader = NULL;
1226 WCHAR *english_family, *localised_family, *StyleW;
1227 DWORD len;
1228 Family *family;
1229 Face *face;
1230 struct list *family_elem_ptr, *face_elem_ptr;
1231 FT_Error err;
1232 FT_Long face_index = 0, num_faces;
1233 #ifdef HAVE_FREETYPE_FTWINFNT_H
1234 FT_WinFNT_HeaderRec winfnt_header;
1235 #endif
1236 int i, bitmap_num, internal_leading;
1237 FONTSIGNATURE fs;
1239 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1240 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1242 #ifdef HAVE_CARBON_CARBON_H
1243 if(file && !fake_family)
1245 char **mac_list = expand_mac_font(file);
1246 if(mac_list)
1248 BOOL had_one = FALSE;
1249 char **cursor;
1250 for(cursor = mac_list; *cursor; cursor++)
1252 had_one = TRUE;
1253 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1254 HeapFree(GetProcessHeap(), 0, *cursor);
1256 HeapFree(GetProcessHeap(), 0, mac_list);
1257 if(had_one)
1258 return 1;
1261 #endif /* HAVE_CARBON_CARBON_H */
1263 do {
1264 char *family_name = fake_family;
1266 if (file)
1268 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1269 err = pFT_New_Face(library, file, face_index, &ft_face);
1270 } else
1272 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1273 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1276 if(err != 0) {
1277 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1278 return 0;
1281 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*/
1282 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1283 pFT_Done_Face(ft_face);
1284 return 0;
1287 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1288 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1289 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1290 pFT_Done_Face(ft_face);
1291 return 0;
1294 if(FT_IS_SFNT(ft_face))
1296 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1297 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1298 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1300 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1301 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1302 pFT_Done_Face(ft_face);
1303 return 0;
1306 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1307 we don't want to load these. */
1308 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1310 FT_ULong len = 0;
1312 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1314 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1315 pFT_Done_Face(ft_face);
1316 return 0;
1321 if(!ft_face->family_name || !ft_face->style_name) {
1322 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1323 pFT_Done_Face(ft_face);
1324 return 0;
1327 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1329 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1330 pFT_Done_Face(ft_face);
1331 return 0;
1334 if (target_family)
1336 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1337 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1339 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1340 HeapFree(GetProcessHeap(), 0, localised_family);
1341 num_faces = ft_face->num_faces;
1342 pFT_Done_Face(ft_face);
1343 continue;
1345 HeapFree(GetProcessHeap(), 0, localised_family);
1348 if(!family_name)
1349 family_name = ft_face->family_name;
1351 bitmap_num = 0;
1352 do {
1353 My_FT_Bitmap_Size *size = NULL;
1354 FT_ULong tmp_size;
1356 if(!FT_IS_SCALABLE(ft_face))
1357 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1359 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1360 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1361 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1363 localised_family = NULL;
1364 if(!fake_family) {
1365 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1366 if(localised_family && !strcmpiW(localised_family, english_family)) {
1367 HeapFree(GetProcessHeap(), 0, localised_family);
1368 localised_family = NULL;
1372 family = NULL;
1373 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1374 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1375 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1376 break;
1377 family = NULL;
1379 if(!family) {
1380 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1381 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1382 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1383 list_init(&family->faces);
1384 list_add_tail(&font_list, &family->entry);
1386 if(localised_family) {
1387 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1388 subst->from.name = strdupW(english_family);
1389 subst->from.charset = -1;
1390 subst->to.name = strdupW(localised_family);
1391 subst->to.charset = -1;
1392 add_font_subst(&font_subst_list, subst, 0);
1395 HeapFree(GetProcessHeap(), 0, localised_family);
1396 HeapFree(GetProcessHeap(), 0, english_family);
1398 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1399 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1400 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1402 internal_leading = 0;
1403 memset(&fs, 0, sizeof(fs));
1405 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1406 if(pOS2) {
1407 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1408 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1409 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1410 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1411 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1412 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1413 if(pOS2->version == 0) {
1414 FT_UInt dummy;
1416 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1417 fs.fsCsb[0] |= FS_LATIN1;
1418 else
1419 fs.fsCsb[0] |= FS_SYMBOL;
1422 #ifdef HAVE_FREETYPE_FTWINFNT_H
1423 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1424 CHARSETINFO csi;
1425 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1426 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1427 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1428 fs = csi.fs;
1429 internal_leading = winfnt_header.internal_leading;
1431 #endif
1433 face_elem_ptr = list_head(&family->faces);
1434 while(face_elem_ptr) {
1435 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1436 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1437 if(!strcmpiW(face->StyleName, StyleW) &&
1438 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1439 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1440 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1441 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1443 if(fake_family) {
1444 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1445 HeapFree(GetProcessHeap(), 0, StyleW);
1446 pFT_Done_Face(ft_face);
1447 return 1;
1449 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1450 TRACE("Original font is newer so skipping this one\n");
1451 HeapFree(GetProcessHeap(), 0, StyleW);
1452 pFT_Done_Face(ft_face);
1453 return 1;
1454 } else {
1455 TRACE("Replacing original with this one\n");
1456 list_remove(&face->entry);
1457 HeapFree(GetProcessHeap(), 0, face->file);
1458 HeapFree(GetProcessHeap(), 0, face->StyleName);
1459 HeapFree(GetProcessHeap(), 0, face->FullName);
1460 HeapFree(GetProcessHeap(), 0, face);
1461 break;
1465 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1466 face->cached_enum_data = NULL;
1467 face->StyleName = StyleW;
1468 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1469 if (file)
1471 face->file = strdupA(file);
1472 face->font_data_ptr = NULL;
1473 face->font_data_size = 0;
1475 else
1477 face->file = NULL;
1478 face->font_data_ptr = font_data_ptr;
1479 face->font_data_size = font_data_size;
1481 face->face_index = face_index;
1482 face->ntmFlags = 0;
1483 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1484 face->ntmFlags |= NTM_ITALIC;
1485 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1486 face->ntmFlags |= NTM_BOLD;
1487 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1488 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1489 face->family = family;
1490 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1491 face->fs = fs;
1492 memset(&face->fs_links, 0, sizeof(face->fs_links));
1494 if(FT_IS_SCALABLE(ft_face)) {
1495 memset(&face->size, 0, sizeof(face->size));
1496 face->scalable = TRUE;
1497 } else {
1498 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1499 size->height, size->width, size->size >> 6,
1500 size->x_ppem >> 6, size->y_ppem >> 6);
1501 face->size.height = size->height;
1502 face->size.width = size->width;
1503 face->size.size = size->size;
1504 face->size.x_ppem = size->x_ppem;
1505 face->size.y_ppem = size->y_ppem;
1506 face->size.internal_leading = internal_leading;
1507 face->scalable = FALSE;
1510 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1511 tmp_size = 0;
1512 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1514 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1515 face->ntmFlags |= NTM_PS_OPENTYPE;
1518 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1519 face->fs.fsCsb[0], face->fs.fsCsb[1],
1520 face->fs.fsUsb[0], face->fs.fsUsb[1],
1521 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1524 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1525 for(i = 0; i < ft_face->num_charmaps; i++) {
1526 switch(ft_face->charmaps[i]->encoding) {
1527 case FT_ENCODING_UNICODE:
1528 case FT_ENCODING_APPLE_ROMAN:
1529 face->fs.fsCsb[0] |= FS_LATIN1;
1530 break;
1531 case FT_ENCODING_MS_SYMBOL:
1532 face->fs.fsCsb[0] |= FS_SYMBOL;
1533 break;
1534 default:
1535 break;
1540 AddFaceToFamily(face, family);
1542 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1544 num_faces = ft_face->num_faces;
1545 pFT_Done_Face(ft_face);
1546 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1547 debugstr_w(StyleW));
1548 } while(num_faces > ++face_index);
1549 return num_faces;
1552 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1554 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1557 static void DumpFontList(void)
1559 Family *family;
1560 Face *face;
1561 struct list *family_elem_ptr, *face_elem_ptr;
1563 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1564 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1565 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1566 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1567 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1568 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1569 if(!face->scalable)
1570 TRACE(" %d", face->size.height);
1571 TRACE("\n");
1574 return;
1577 /***********************************************************
1578 * The replacement list is a way to map an entire font
1579 * family onto another family. For example adding
1581 * [HKCU\Software\Wine\Fonts\Replacements]
1582 * "Wingdings"="Winedings"
1584 * would enumerate the Winedings font both as Winedings and
1585 * Wingdings. However if a real Wingdings font is present the
1586 * replacement does not take place.
1589 static void LoadReplaceList(void)
1591 HKEY hkey;
1592 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1593 LPWSTR value;
1594 LPVOID data;
1595 Family *family;
1596 Face *face;
1597 struct list *family_elem_ptr, *face_elem_ptr;
1598 CHAR familyA[400];
1600 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1601 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1603 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1604 &valuelen, &datalen, NULL, NULL);
1606 valuelen++; /* returned value doesn't include room for '\0' */
1607 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1608 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1610 dlen = datalen;
1611 vlen = valuelen;
1612 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1613 &dlen) == ERROR_SUCCESS) {
1614 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1615 /* "NewName"="Oldname" */
1616 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1618 if(!find_family_from_name(value))
1620 /* Find the old family and hence all of the font files
1621 in that family */
1622 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1623 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1624 if(!strcmpiW(family->FamilyName, data)) {
1625 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1626 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1627 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1628 debugstr_w(face->StyleName), familyA);
1629 /* Now add a new entry with the new family name */
1630 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1631 familyA, family->FamilyName,
1632 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1634 break;
1638 /* reset dlen and vlen */
1639 dlen = datalen;
1640 vlen = valuelen;
1642 HeapFree(GetProcessHeap(), 0, data);
1643 HeapFree(GetProcessHeap(), 0, value);
1644 RegCloseKey(hkey);
1648 /*************************************************************
1649 * init_system_links
1651 static BOOL init_system_links(void)
1653 HKEY hkey;
1654 BOOL ret = FALSE;
1655 DWORD type, max_val, max_data, val_len, data_len, index;
1656 WCHAR *value, *data;
1657 WCHAR *entry, *next;
1658 SYSTEM_LINKS *font_link, *system_font_link;
1659 CHILD_FONT *child_font;
1660 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1661 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1662 FONTSIGNATURE fs;
1663 Family *family;
1664 Face *face;
1665 FontSubst *psub;
1667 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1669 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1670 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1671 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1672 val_len = max_val + 1;
1673 data_len = max_data;
1674 index = 0;
1675 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1677 memset(&fs, 0, sizeof(fs));
1678 psub = get_font_subst(&font_subst_list, value, -1);
1679 /* Don't store fonts that are only substitutes for other fonts */
1680 if(psub)
1682 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1683 goto next;
1685 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1686 font_link->font_name = strdupW(value);
1687 list_init(&font_link->links);
1688 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1690 WCHAR *face_name;
1691 CHILD_FONT *child_font;
1693 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1695 next = entry + strlenW(entry) + 1;
1697 face_name = strchrW(entry, ',');
1698 if(face_name)
1700 *face_name++ = 0;
1701 while(isspaceW(*face_name))
1702 face_name++;
1704 psub = get_font_subst(&font_subst_list, face_name, -1);
1705 if(psub)
1706 face_name = psub->to.name;
1708 face = find_face_from_filename(entry, face_name);
1709 if(!face)
1711 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1712 continue;
1715 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1716 child_font->face = face;
1717 child_font->font = NULL;
1718 fs.fsCsb[0] |= face->fs.fsCsb[0];
1719 fs.fsCsb[1] |= face->fs.fsCsb[1];
1720 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1721 list_add_tail(&font_link->links, &child_font->entry);
1723 family = find_family_from_name(font_link->font_name);
1724 if(family)
1726 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1728 face->fs_links = fs;
1731 list_add_tail(&system_links, &font_link->entry);
1732 next:
1733 val_len = max_val + 1;
1734 data_len = max_data;
1737 HeapFree(GetProcessHeap(), 0, value);
1738 HeapFree(GetProcessHeap(), 0, data);
1739 RegCloseKey(hkey);
1742 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1743 that Tahoma has */
1745 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1746 system_font_link->font_name = strdupW(System);
1747 list_init(&system_font_link->links);
1749 face = find_face_from_filename(tahoma_ttf, Tahoma);
1750 if(face)
1752 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1753 child_font->face = face;
1754 child_font->font = NULL;
1755 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1756 list_add_tail(&system_font_link->links, &child_font->entry);
1758 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1760 if(!strcmpiW(font_link->font_name, Tahoma))
1762 CHILD_FONT *font_link_entry;
1763 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1765 CHILD_FONT *new_child;
1766 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1767 new_child->face = font_link_entry->face;
1768 new_child->font = NULL;
1769 list_add_tail(&system_font_link->links, &new_child->entry);
1771 break;
1774 list_add_tail(&system_links, &system_font_link->entry);
1775 return ret;
1778 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1780 DIR *dir;
1781 struct dirent *dent;
1782 char path[MAX_PATH];
1784 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1786 dir = opendir(dirname);
1787 if(!dir) {
1788 WARN("Can't open directory %s\n", debugstr_a(dirname));
1789 return FALSE;
1791 while((dent = readdir(dir)) != NULL) {
1792 struct stat statbuf;
1794 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1795 continue;
1797 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1799 sprintf(path, "%s/%s", dirname, dent->d_name);
1801 if(stat(path, &statbuf) == -1)
1803 WARN("Can't stat %s\n", debugstr_a(path));
1804 continue;
1806 if(S_ISDIR(statbuf.st_mode))
1807 ReadFontDir(path, external_fonts);
1808 else
1809 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1811 closedir(dir);
1812 return TRUE;
1815 static void load_fontconfig_fonts(void)
1817 #ifdef SONAME_LIBFONTCONFIG
1818 void *fc_handle = NULL;
1819 FcConfig *config;
1820 FcPattern *pat;
1821 FcObjectSet *os;
1822 FcFontSet *fontset;
1823 int i, len;
1824 char *file;
1825 const char *ext;
1827 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1828 if(!fc_handle) {
1829 TRACE("Wine cannot find the fontconfig library (%s).\n",
1830 SONAME_LIBFONTCONFIG);
1831 return;
1833 #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;}
1834 LOAD_FUNCPTR(FcConfigGetCurrent);
1835 LOAD_FUNCPTR(FcFontList);
1836 LOAD_FUNCPTR(FcFontSetDestroy);
1837 LOAD_FUNCPTR(FcInit);
1838 LOAD_FUNCPTR(FcObjectSetAdd);
1839 LOAD_FUNCPTR(FcObjectSetCreate);
1840 LOAD_FUNCPTR(FcObjectSetDestroy);
1841 LOAD_FUNCPTR(FcPatternCreate);
1842 LOAD_FUNCPTR(FcPatternDestroy);
1843 LOAD_FUNCPTR(FcPatternGetBool);
1844 LOAD_FUNCPTR(FcPatternGetString);
1845 #undef LOAD_FUNCPTR
1847 if(!pFcInit()) return;
1849 config = pFcConfigGetCurrent();
1850 pat = pFcPatternCreate();
1851 os = pFcObjectSetCreate();
1852 pFcObjectSetAdd(os, FC_FILE);
1853 pFcObjectSetAdd(os, FC_SCALABLE);
1854 fontset = pFcFontList(config, pat, os);
1855 if(!fontset) return;
1856 for(i = 0; i < fontset->nfont; i++) {
1857 FcBool scalable;
1859 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1860 continue;
1861 TRACE("fontconfig: %s\n", file);
1863 /* We're just interested in OT/TT fonts for now, so this hack just
1864 picks up the scalable fonts without extensions .pf[ab] to save time
1865 loading every other font */
1867 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1869 TRACE("not scalable\n");
1870 continue;
1873 len = strlen( file );
1874 if(len < 4) continue;
1875 ext = &file[ len - 3 ];
1876 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1877 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1879 pFcFontSetDestroy(fontset);
1880 pFcObjectSetDestroy(os);
1881 pFcPatternDestroy(pat);
1882 sym_not_found:
1883 #endif
1884 return;
1887 static BOOL load_font_from_data_dir(LPCWSTR file)
1889 BOOL ret = FALSE;
1890 const char *data_dir = wine_get_data_dir();
1892 if (!data_dir) data_dir = wine_get_build_dir();
1894 if (data_dir)
1896 INT len;
1897 char *unix_name;
1899 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1901 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1903 strcpy(unix_name, data_dir);
1904 strcat(unix_name, "/fonts/");
1906 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1908 EnterCriticalSection( &freetype_cs );
1909 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1910 LeaveCriticalSection( &freetype_cs );
1911 HeapFree(GetProcessHeap(), 0, unix_name);
1913 return ret;
1916 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1918 static const WCHAR slashW[] = {'\\','\0'};
1919 BOOL ret = FALSE;
1920 WCHAR windowsdir[MAX_PATH];
1921 char *unixname;
1923 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1924 strcatW(windowsdir, fontsW);
1925 strcatW(windowsdir, slashW);
1926 strcatW(windowsdir, file);
1927 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1928 EnterCriticalSection( &freetype_cs );
1929 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1930 LeaveCriticalSection( &freetype_cs );
1931 HeapFree(GetProcessHeap(), 0, unixname);
1933 return ret;
1936 static void load_system_fonts(void)
1938 HKEY hkey;
1939 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1940 const WCHAR * const *value;
1941 DWORD dlen, type;
1942 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1943 char *unixname;
1945 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1946 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1947 strcatW(windowsdir, fontsW);
1948 for(value = SystemFontValues; *value; value++) {
1949 dlen = sizeof(data);
1950 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1951 type == REG_SZ) {
1952 BOOL added = FALSE;
1954 sprintfW(pathW, fmtW, windowsdir, data);
1955 if((unixname = wine_get_unix_file_name(pathW))) {
1956 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1957 HeapFree(GetProcessHeap(), 0, unixname);
1959 if (!added)
1960 load_font_from_data_dir(data);
1963 RegCloseKey(hkey);
1967 /*************************************************************
1969 * This adds registry entries for any externally loaded fonts
1970 * (fonts from fontconfig or FontDirs). It also deletes entries
1971 * of no longer existing fonts.
1974 static void update_reg_entries(void)
1976 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1977 LPWSTR valueW;
1978 DWORD len, len_fam;
1979 Family *family;
1980 Face *face;
1981 struct list *family_elem_ptr, *face_elem_ptr;
1982 WCHAR *file;
1983 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1984 static const WCHAR spaceW[] = {' ', '\0'};
1985 char *path;
1987 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1988 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1989 ERR("Can't create Windows font reg key\n");
1990 goto end;
1993 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1994 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1995 ERR("Can't create Windows font reg key\n");
1996 goto end;
1999 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2000 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2001 ERR("Can't create external font reg key\n");
2002 goto end;
2005 /* enumerate the fonts and add external ones to the two keys */
2007 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2008 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2009 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2010 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2011 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2012 if(!face->external) continue;
2013 len = len_fam;
2014 if (!(face->ntmFlags & NTM_REGULAR))
2015 len = len_fam + strlenW(face->StyleName) + 1;
2016 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2017 strcpyW(valueW, family->FamilyName);
2018 if(len != len_fam) {
2019 strcatW(valueW, spaceW);
2020 strcatW(valueW, face->StyleName);
2022 strcatW(valueW, TrueType);
2024 file = wine_get_dos_file_name(face->file);
2025 if(file)
2026 len = strlenW(file) + 1;
2027 else
2029 if((path = strrchr(face->file, '/')) == NULL)
2030 path = face->file;
2031 else
2032 path++;
2033 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2035 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2036 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2038 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2039 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2040 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2042 HeapFree(GetProcessHeap(), 0, file);
2043 HeapFree(GetProcessHeap(), 0, valueW);
2046 end:
2047 if(external_key) RegCloseKey(external_key);
2048 if(win9x_key) RegCloseKey(win9x_key);
2049 if(winnt_key) RegCloseKey(winnt_key);
2050 return;
2053 static void delete_external_font_keys(void)
2055 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2056 DWORD dlen, vlen, datalen, valuelen, i, type;
2057 LPWSTR valueW;
2058 LPVOID data;
2060 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2061 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2062 ERR("Can't create Windows font reg key\n");
2063 goto end;
2066 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2067 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2068 ERR("Can't create Windows font reg key\n");
2069 goto end;
2072 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2073 ERR("Can't create external font reg key\n");
2074 goto end;
2077 /* Delete all external fonts added last time */
2079 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2080 &valuelen, &datalen, NULL, NULL);
2081 valuelen++; /* returned value doesn't include room for '\0' */
2082 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2083 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2085 dlen = datalen * sizeof(WCHAR);
2086 vlen = valuelen;
2087 i = 0;
2088 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2089 &dlen) == ERROR_SUCCESS) {
2091 RegDeleteValueW(winnt_key, valueW);
2092 RegDeleteValueW(win9x_key, valueW);
2093 /* reset dlen and vlen */
2094 dlen = datalen;
2095 vlen = valuelen;
2097 HeapFree(GetProcessHeap(), 0, data);
2098 HeapFree(GetProcessHeap(), 0, valueW);
2100 /* Delete the old external fonts key */
2101 RegCloseKey(external_key);
2102 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2104 end:
2105 if(win9x_key) RegCloseKey(win9x_key);
2106 if(winnt_key) RegCloseKey(winnt_key);
2109 /*************************************************************
2110 * WineEngAddFontResourceEx
2113 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2115 INT ret = 0;
2117 GDI_CheckNotLock();
2119 if (ft_handle) /* do it only if we have freetype up and running */
2121 char *unixname;
2123 if(flags)
2124 FIXME("Ignoring flags %x\n", flags);
2126 if((unixname = wine_get_unix_file_name(file)))
2128 EnterCriticalSection( &freetype_cs );
2129 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2130 LeaveCriticalSection( &freetype_cs );
2131 HeapFree(GetProcessHeap(), 0, unixname);
2133 if (!ret && !strchrW(file, '\\')) {
2134 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2135 ret = load_font_from_winfonts_dir(file);
2136 if (!ret) {
2137 /* Try in datadir/fonts (or builddir/fonts),
2138 * needed for Magic the Gathering Online
2140 ret = load_font_from_data_dir(file);
2144 return ret;
2147 /*************************************************************
2148 * WineEngAddFontMemResourceEx
2151 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2153 GDI_CheckNotLock();
2155 if (ft_handle) /* do it only if we have freetype up and running */
2157 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2159 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2160 memcpy(pFontCopy, pbFont, cbFont);
2162 EnterCriticalSection( &freetype_cs );
2163 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2164 LeaveCriticalSection( &freetype_cs );
2166 if (*pcFonts == 0)
2168 TRACE("AddFontToList failed\n");
2169 HeapFree(GetProcessHeap(), 0, pFontCopy);
2170 return 0;
2172 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2173 * For now return something unique but quite random
2175 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2176 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2179 *pcFonts = 0;
2180 return 0;
2183 /*************************************************************
2184 * WineEngRemoveFontResourceEx
2187 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2189 GDI_CheckNotLock();
2190 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2191 return TRUE;
2194 static const struct nls_update_font_list
2196 UINT ansi_cp, oem_cp;
2197 const char *oem, *fixed, *system;
2198 const char *courier, *serif, *small, *sserif;
2199 /* these are for font substitutes */
2200 const char *shelldlg, *tmsrmn;
2201 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2202 *helv_0, *tmsrmn_0;
2203 const struct subst
2205 const char *from, *to;
2206 } arial_0, courier_new_0, times_new_roman_0;
2207 } nls_update_font_list[] =
2209 /* Latin 1 (United States) */
2210 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2211 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2212 "Tahoma","Times New Roman",
2213 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2214 { 0 }, { 0 }, { 0 }
2216 /* Latin 1 (Multilingual) */
2217 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2218 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2219 "Tahoma","Times New Roman", /* FIXME unverified */
2220 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2221 { 0 }, { 0 }, { 0 }
2223 /* Eastern Europe */
2224 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2225 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2226 "Tahoma","Times New Roman", /* FIXME unverified */
2227 "Fixedsys,238", "System,238",
2228 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2229 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2230 { "Arial CE,0", "Arial,238" },
2231 { "Courier New CE,0", "Courier New,238" },
2232 { "Times New Roman CE,0", "Times New Roman,238" }
2234 /* Cyrillic */
2235 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2236 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2237 "Tahoma","Times New Roman", /* FIXME unverified */
2238 "Fixedsys,204", "System,204",
2239 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2240 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2241 { "Arial Cyr,0", "Arial,204" },
2242 { "Courier New Cyr,0", "Courier New,204" },
2243 { "Times New Roman Cyr,0", "Times New Roman,204" }
2245 /* Greek */
2246 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2247 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2248 "Tahoma","Times New Roman", /* FIXME unverified */
2249 "Fixedsys,161", "System,161",
2250 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2251 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2252 { "Arial Greek,0", "Arial,161" },
2253 { "Courier New Greek,0", "Courier New,161" },
2254 { "Times New Roman Greek,0", "Times New Roman,161" }
2256 /* Turkish */
2257 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2258 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2259 "Tahoma","Times New Roman", /* FIXME unverified */
2260 "Fixedsys,162", "System,162",
2261 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2262 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2263 { "Arial Tur,0", "Arial,162" },
2264 { "Courier New Tur,0", "Courier New,162" },
2265 { "Times New Roman Tur,0", "Times New Roman,162" }
2267 /* Hebrew */
2268 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2269 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2270 "Tahoma","Times New Roman", /* FIXME unverified */
2271 "Fixedsys,177", "System,177",
2272 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2273 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2274 { 0 }, { 0 }, { 0 }
2276 /* Arabic */
2277 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2278 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2279 "Tahoma","Times New Roman", /* FIXME unverified */
2280 "Fixedsys,178", "System,178",
2281 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2282 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2283 { 0 }, { 0 }, { 0 }
2285 /* Baltic */
2286 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2287 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2288 "Tahoma","Times New Roman", /* FIXME unverified */
2289 "Fixedsys,186", "System,186",
2290 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2291 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2292 { "Arial Baltic,0", "Arial,186" },
2293 { "Courier New Baltic,0", "Courier New,186" },
2294 { "Times New Roman Baltic,0", "Times New Roman,186" }
2296 /* Vietnamese */
2297 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2299 "Tahoma","Times New Roman", /* FIXME unverified */
2300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2301 { 0 }, { 0 }, { 0 }
2303 /* Thai */
2304 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2306 "Tahoma","Times New Roman", /* FIXME unverified */
2307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2308 { 0 }, { 0 }, { 0 }
2310 /* Japanese */
2311 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2312 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2313 "MS UI Gothic","MS Serif",
2314 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2315 { 0 }, { 0 }, { 0 }
2317 /* Chinese Simplified */
2318 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2319 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2320 "SimSun", "NSimSun",
2321 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2322 { 0 }, { 0 }, { 0 }
2324 /* Korean */
2325 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2327 "Gulim", "Batang",
2328 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2329 { 0 }, { 0 }, { 0 }
2331 /* Chinese Traditional */
2332 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2334 "PMingLiU", "MingLiU",
2335 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2336 { 0 }, { 0 }, { 0 }
2340 static const WCHAR *font_links_list[] =
2342 Lucida_Sans_Unicode,
2343 Microsoft_Sans_Serif,
2344 Tahoma
2347 static const struct font_links_defaults_list
2349 /* Keyed off substitution for "MS Shell Dlg" */
2350 const WCHAR *shelldlg;
2351 /* Maximum of four substitutes, plus terminating NULL pointer */
2352 const WCHAR *substitutes[5];
2353 } font_links_defaults_list[] =
2355 /* Non East-Asian */
2356 { Tahoma, /* FIXME unverified ordering */
2357 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2359 /* Below lists are courtesy of
2360 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2362 /* Japanese */
2363 { MS_UI_Gothic,
2364 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2366 /* Chinese Simplified */
2367 { SimSun,
2368 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2370 /* Korean */
2371 { Gulim,
2372 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2374 /* Chinese Traditional */
2375 { PMingLiU,
2376 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2380 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2382 return ( ansi_cp == 932 /* CP932 for Japanese */
2383 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2384 || ansi_cp == 949 /* CP949 for Korean */
2385 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2388 static inline HKEY create_fonts_NT_registry_key(void)
2390 HKEY hkey = 0;
2392 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2393 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2394 return hkey;
2397 static inline HKEY create_fonts_9x_registry_key(void)
2399 HKEY hkey = 0;
2401 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2402 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2403 return hkey;
2406 static inline HKEY create_config_fonts_registry_key(void)
2408 HKEY hkey = 0;
2410 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2411 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2412 return hkey;
2415 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2417 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2418 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2419 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2420 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2423 static void set_value_key(HKEY hkey, const char *name, const char *value)
2425 if (value)
2426 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2427 else if (name)
2428 RegDeleteValueA(hkey, name);
2431 static void update_font_info(void)
2433 char buf[40], cpbuf[40];
2434 DWORD len, type;
2435 HKEY hkey = 0;
2436 UINT i, ansi_cp = 0, oem_cp = 0;
2437 BOOL done = FALSE;
2439 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2440 return;
2442 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2443 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2444 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2445 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2446 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2448 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2449 if (is_dbcs_ansi_cp(ansi_cp))
2450 use_default_fallback = TRUE;
2452 len = sizeof(buf);
2453 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2455 if (!strcmp( buf, cpbuf )) /* already set correctly */
2457 RegCloseKey(hkey);
2458 return;
2460 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2462 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2464 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2465 RegCloseKey(hkey);
2467 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2469 HKEY hkey;
2471 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2472 nls_update_font_list[i].oem_cp == oem_cp)
2474 hkey = create_config_fonts_registry_key();
2475 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2476 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2477 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2478 RegCloseKey(hkey);
2480 hkey = create_fonts_NT_registry_key();
2481 add_font_list(hkey, &nls_update_font_list[i]);
2482 RegCloseKey(hkey);
2484 hkey = create_fonts_9x_registry_key();
2485 add_font_list(hkey, &nls_update_font_list[i]);
2486 RegCloseKey(hkey);
2488 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2490 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2491 strlen(nls_update_font_list[i].shelldlg)+1);
2492 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2493 strlen(nls_update_font_list[i].tmsrmn)+1);
2495 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2496 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2497 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2498 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2499 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2500 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2501 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2502 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2504 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2505 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2506 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2508 RegCloseKey(hkey);
2510 done = TRUE;
2512 else
2514 /* Delete the FontSubstitutes from other locales */
2515 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2517 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2518 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2519 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2520 RegCloseKey(hkey);
2524 if (!done)
2525 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2527 /* Clear out system links */
2528 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2531 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2533 const WCHAR *value;
2534 int i;
2535 FontSubst *psub;
2536 Family *family;
2537 Face *face;
2538 const char *file;
2539 WCHAR *fileW;
2540 int fileLen;
2541 WCHAR buff[MAX_PATH];
2542 WCHAR *data;
2543 int entryLen;
2545 static const WCHAR comma[] = {',',0};
2547 RegDeleteValueW(hkey, name);
2548 if (values)
2550 data = buff;
2551 data[0] = '\0';
2552 for (i = 0; values[i] != NULL; i++)
2554 value = values[i];
2555 if (!strcmpiW(name,value))
2556 continue;
2557 psub = get_font_subst(&font_subst_list, value, -1);
2558 if(psub)
2559 value = psub->to.name;
2560 family = find_family_from_name(value);
2561 if (!family)
2562 continue;
2563 file = NULL;
2564 /* Use first extant filename for this Family */
2565 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2567 if (!face->file)
2568 continue;
2569 file = strrchr(face->file, '/');
2570 if (!file)
2571 file = face->file;
2572 else
2573 file++;
2574 break;
2576 if (!file)
2577 continue;
2578 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2579 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2580 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2581 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2582 if (sizeof(buff)-(data-buff) < entryLen + 1)
2584 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2585 HeapFree(GetProcessHeap(), 0, fileW);
2586 break;
2588 strcpyW(data, fileW);
2589 strcatW(data, comma);
2590 strcatW(data, value);
2591 data += entryLen;
2592 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2593 HeapFree(GetProcessHeap(), 0, fileW);
2595 if (data != buff)
2597 *data='\0';
2598 data++;
2599 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2600 } else
2601 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2602 } else
2603 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2606 static void update_system_links(void)
2608 HKEY hkey = 0;
2609 UINT i, j;
2610 BOOL done = FALSE;
2611 DWORD disposition;
2612 FontSubst *psub;
2614 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2616 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2618 if (disposition == REG_OPENED_EXISTING_KEY)
2620 TRACE("SystemLink key already exists, doing nothing\n");
2621 RegCloseKey(hkey);
2622 return;
2625 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2626 if (!psub) {
2627 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2628 RegCloseKey(hkey);
2629 return;
2632 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2634 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2636 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2637 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2639 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2640 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2641 done = TRUE;
2643 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2645 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2648 RegCloseKey(hkey);
2649 if (!done)
2650 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2651 } else
2652 WARN("failed to create SystemLink key\n");
2656 static BOOL init_freetype(void)
2658 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2659 if(!ft_handle) {
2660 WINE_MESSAGE(
2661 "Wine cannot find the FreeType font library. To enable Wine to\n"
2662 "use TrueType fonts please install a version of FreeType greater than\n"
2663 "or equal to 2.0.5.\n"
2664 "http://www.freetype.org\n");
2665 return FALSE;
2668 #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;}
2670 LOAD_FUNCPTR(FT_Vector_Unit)
2671 LOAD_FUNCPTR(FT_Done_Face)
2672 LOAD_FUNCPTR(FT_Get_Char_Index)
2673 LOAD_FUNCPTR(FT_Get_Module)
2674 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2675 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2676 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2677 LOAD_FUNCPTR(FT_Init_FreeType)
2678 LOAD_FUNCPTR(FT_Load_Glyph)
2679 LOAD_FUNCPTR(FT_Matrix_Multiply)
2680 #ifndef FT_MULFIX_INLINED
2681 LOAD_FUNCPTR(FT_MulFix)
2682 #endif
2683 LOAD_FUNCPTR(FT_New_Face)
2684 LOAD_FUNCPTR(FT_New_Memory_Face)
2685 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2686 LOAD_FUNCPTR(FT_Outline_Transform)
2687 LOAD_FUNCPTR(FT_Outline_Translate)
2688 LOAD_FUNCPTR(FT_Select_Charmap)
2689 LOAD_FUNCPTR(FT_Set_Charmap)
2690 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2691 LOAD_FUNCPTR(FT_Vector_Transform)
2692 LOAD_FUNCPTR(FT_Render_Glyph)
2694 #undef LOAD_FUNCPTR
2695 /* Don't warn if these ones are missing */
2696 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2697 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2698 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2699 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2700 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2701 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2702 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2703 #endif
2704 #ifdef HAVE_FREETYPE_FTWINFNT_H
2705 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2706 #endif
2707 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2708 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2709 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2710 <= 2.0.3 has FT_Sqrt64 */
2711 goto sym_not_found;
2714 if(pFT_Init_FreeType(&library) != 0) {
2715 ERR("Can't init FreeType library\n");
2716 wine_dlclose(ft_handle, NULL, 0);
2717 ft_handle = NULL;
2718 return FALSE;
2720 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2721 if (pFT_Library_Version)
2722 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2724 if (FT_Version.major<=0)
2726 FT_Version.major=2;
2727 FT_Version.minor=0;
2728 FT_Version.patch=5;
2730 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2731 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2732 ((FT_Version.minor << 8) & 0x00ff00) |
2733 ((FT_Version.patch ) & 0x0000ff);
2735 return TRUE;
2737 sym_not_found:
2738 WINE_MESSAGE(
2739 "Wine cannot find certain functions that it needs inside the FreeType\n"
2740 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2741 "FreeType to at least version 2.0.5.\n"
2742 "http://www.freetype.org\n");
2743 wine_dlclose(ft_handle, NULL, 0);
2744 ft_handle = NULL;
2745 return FALSE;
2748 /*************************************************************
2749 * WineEngInit
2751 * Initialize FreeType library and create a list of available faces
2753 BOOL WineEngInit(void)
2755 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2756 static const WCHAR pathW[] = {'P','a','t','h',0};
2757 HKEY hkey;
2758 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2759 WCHAR windowsdir[MAX_PATH];
2760 char *unixname;
2761 HANDLE font_mutex;
2762 const char *data_dir;
2764 TRACE("\n");
2766 /* update locale dependent font info in registry */
2767 update_font_info();
2769 if(!init_freetype()) return FALSE;
2771 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2772 ERR("Failed to create font mutex\n");
2773 return FALSE;
2775 WaitForSingleObject(font_mutex, INFINITE);
2777 delete_external_font_keys();
2779 /* load the system bitmap fonts */
2780 load_system_fonts();
2782 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2783 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2784 strcatW(windowsdir, fontsW);
2785 if((unixname = wine_get_unix_file_name(windowsdir)))
2787 ReadFontDir(unixname, FALSE);
2788 HeapFree(GetProcessHeap(), 0, unixname);
2791 /* load the system truetype fonts */
2792 data_dir = wine_get_data_dir();
2793 if (!data_dir) data_dir = wine_get_build_dir();
2794 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2795 strcpy(unixname, data_dir);
2796 strcat(unixname, "/fonts/");
2797 ReadFontDir(unixname, TRUE);
2798 HeapFree(GetProcessHeap(), 0, unixname);
2801 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2802 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2803 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2804 will skip these. */
2805 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2806 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2807 &hkey) == ERROR_SUCCESS) {
2808 LPWSTR data, valueW;
2809 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2810 &valuelen, &datalen, NULL, NULL);
2812 valuelen++; /* returned value doesn't include room for '\0' */
2813 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2814 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2815 if (valueW && data)
2817 dlen = datalen * sizeof(WCHAR);
2818 vlen = valuelen;
2819 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2820 &dlen) == ERROR_SUCCESS) {
2821 if(data[0] && (data[1] == ':'))
2823 if((unixname = wine_get_unix_file_name(data)))
2825 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2826 HeapFree(GetProcessHeap(), 0, unixname);
2829 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2831 WCHAR pathW[MAX_PATH];
2832 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2833 BOOL added = FALSE;
2835 sprintfW(pathW, fmtW, windowsdir, data);
2836 if((unixname = wine_get_unix_file_name(pathW)))
2838 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2839 HeapFree(GetProcessHeap(), 0, unixname);
2841 if (!added)
2842 load_font_from_data_dir(data);
2844 /* reset dlen and vlen */
2845 dlen = datalen;
2846 vlen = valuelen;
2849 HeapFree(GetProcessHeap(), 0, data);
2850 HeapFree(GetProcessHeap(), 0, valueW);
2851 RegCloseKey(hkey);
2854 load_fontconfig_fonts();
2856 /* then look in any directories that we've specified in the config file */
2857 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2858 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2860 DWORD len;
2861 LPWSTR valueW;
2862 LPSTR valueA, ptr;
2864 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2866 len += sizeof(WCHAR);
2867 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2868 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2870 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2871 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2872 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2873 TRACE( "got font path %s\n", debugstr_a(valueA) );
2874 ptr = valueA;
2875 while (ptr)
2877 LPSTR next = strchr( ptr, ':' );
2878 if (next) *next++ = 0;
2879 ReadFontDir( ptr, TRUE );
2880 ptr = next;
2882 HeapFree( GetProcessHeap(), 0, valueA );
2884 HeapFree( GetProcessHeap(), 0, valueW );
2886 RegCloseKey(hkey);
2889 DumpFontList();
2890 LoadSubstList();
2891 DumpSubstList();
2892 LoadReplaceList();
2893 update_reg_entries();
2895 update_system_links();
2896 init_system_links();
2898 ReleaseMutex(font_mutex);
2899 return TRUE;
2903 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2905 TT_OS2 *pOS2;
2906 TT_HoriHeader *pHori;
2908 LONG ppem;
2910 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2911 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2913 if(height == 0) height = 16;
2915 /* Calc. height of EM square:
2917 * For +ve lfHeight we have
2918 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2919 * Re-arranging gives:
2920 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2922 * For -ve lfHeight we have
2923 * |lfHeight| = ppem
2924 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2925 * with il = winAscent + winDescent - units_per_em]
2929 if(height > 0) {
2930 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2931 ppem = MulDiv(ft_face->units_per_EM, height,
2932 pHori->Ascender - pHori->Descender);
2933 else
2934 ppem = MulDiv(ft_face->units_per_EM, height,
2935 pOS2->usWinAscent + pOS2->usWinDescent);
2937 else
2938 ppem = -height;
2940 return ppem;
2943 static struct font_mapping *map_font_file( const char *name )
2945 struct font_mapping *mapping;
2946 struct stat st;
2947 int fd;
2949 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2950 if (fstat( fd, &st ) == -1) goto error;
2952 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2954 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2956 mapping->refcount++;
2957 close( fd );
2958 return mapping;
2961 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2962 goto error;
2964 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2965 close( fd );
2967 if (mapping->data == MAP_FAILED)
2969 HeapFree( GetProcessHeap(), 0, mapping );
2970 return NULL;
2972 mapping->refcount = 1;
2973 mapping->dev = st.st_dev;
2974 mapping->ino = st.st_ino;
2975 mapping->size = st.st_size;
2976 list_add_tail( &mappings_list, &mapping->entry );
2977 return mapping;
2979 error:
2980 close( fd );
2981 return NULL;
2984 static void unmap_font_file( struct font_mapping *mapping )
2986 if (!--mapping->refcount)
2988 list_remove( &mapping->entry );
2989 munmap( mapping->data, mapping->size );
2990 HeapFree( GetProcessHeap(), 0, mapping );
2994 static LONG load_VDMX(GdiFont*, LONG);
2996 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2998 FT_Error err;
2999 FT_Face ft_face;
3000 void *data_ptr;
3001 DWORD data_size;
3003 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3005 if (face->file)
3007 if (!(font->mapping = map_font_file( face->file )))
3009 WARN("failed to map %s\n", debugstr_a(face->file));
3010 return 0;
3012 data_ptr = font->mapping->data;
3013 data_size = font->mapping->size;
3015 else
3017 data_ptr = face->font_data_ptr;
3018 data_size = face->font_data_size;
3021 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3022 if(err) {
3023 ERR("FT_New_Face rets %d\n", err);
3024 return 0;
3027 /* set it here, as load_VDMX needs it */
3028 font->ft_face = ft_face;
3030 if(FT_IS_SCALABLE(ft_face)) {
3031 /* load the VDMX table if we have one */
3032 font->ppem = load_VDMX(font, height);
3033 if(font->ppem == 0)
3034 font->ppem = calc_ppem_for_height(ft_face, height);
3035 TRACE("height %d => ppem %d\n", height, font->ppem);
3037 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3038 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3039 } else {
3040 font->ppem = height;
3041 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3042 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3044 return ft_face;
3048 static int get_nearest_charset(Face *face, int *cp)
3050 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3051 a single face with the requested charset. The idea is to check if
3052 the selected font supports the current ANSI codepage, if it does
3053 return the corresponding charset, else return the first charset */
3055 CHARSETINFO csi;
3056 int acp = GetACP(), i;
3057 DWORD fs0;
3059 *cp = acp;
3060 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3061 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3062 return csi.ciCharset;
3064 for(i = 0; i < 32; i++) {
3065 fs0 = 1L << i;
3066 if(face->fs.fsCsb[0] & fs0) {
3067 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3068 *cp = csi.ciACP;
3069 return csi.ciCharset;
3071 else
3072 FIXME("TCI failing on %x\n", fs0);
3076 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3077 face->fs.fsCsb[0], face->file);
3078 *cp = acp;
3079 return DEFAULT_CHARSET;
3082 static GdiFont *alloc_font(void)
3084 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3085 ret->gmsize = 1;
3086 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3087 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3088 ret->potm = NULL;
3089 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3090 ret->total_kern_pairs = (DWORD)-1;
3091 ret->kern_pairs = NULL;
3092 list_init(&ret->hfontlist);
3093 list_init(&ret->child_fonts);
3094 return ret;
3097 static void free_font(GdiFont *font)
3099 struct list *cursor, *cursor2;
3100 DWORD i;
3102 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3104 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3105 list_remove(cursor);
3106 if(child->font)
3107 free_font(child->font);
3108 HeapFree(GetProcessHeap(), 0, child);
3111 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3113 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3114 DeleteObject(hfontlist->hfont);
3115 list_remove(&hfontlist->entry);
3116 HeapFree(GetProcessHeap(), 0, hfontlist);
3119 if (font->ft_face) pFT_Done_Face(font->ft_face);
3120 if (font->mapping) unmap_font_file( font->mapping );
3121 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3122 HeapFree(GetProcessHeap(), 0, font->potm);
3123 HeapFree(GetProcessHeap(), 0, font->name);
3124 for (i = 0; i < font->gmsize; i++)
3125 HeapFree(GetProcessHeap(),0,font->gm[i]);
3126 HeapFree(GetProcessHeap(), 0, font->gm);
3127 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3128 HeapFree(GetProcessHeap(), 0, font);
3132 /*************************************************************
3133 * load_VDMX
3135 * load the vdmx entry for the specified height
3138 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3139 ( ( (FT_ULong)_x4 << 24 ) | \
3140 ( (FT_ULong)_x3 << 16 ) | \
3141 ( (FT_ULong)_x2 << 8 ) | \
3142 (FT_ULong)_x1 )
3144 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3146 typedef struct {
3147 BYTE bCharSet;
3148 BYTE xRatio;
3149 BYTE yStartRatio;
3150 BYTE yEndRatio;
3151 } Ratios;
3153 typedef struct {
3154 WORD recs;
3155 BYTE startsz;
3156 BYTE endsz;
3157 } VDMX_group;
3159 static LONG load_VDMX(GdiFont *font, LONG height)
3161 WORD hdr[3], tmp;
3162 VDMX_group group;
3163 BYTE devXRatio, devYRatio;
3164 USHORT numRecs, numRatios;
3165 DWORD result, offset = -1;
3166 LONG ppem = 0;
3167 int i;
3169 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3171 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3172 return ppem;
3174 /* FIXME: need the real device aspect ratio */
3175 devXRatio = 1;
3176 devYRatio = 1;
3178 numRecs = GET_BE_WORD(hdr[1]);
3179 numRatios = GET_BE_WORD(hdr[2]);
3181 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3182 for(i = 0; i < numRatios; i++) {
3183 Ratios ratio;
3185 offset = (3 * 2) + (i * sizeof(Ratios));
3186 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3187 offset = -1;
3189 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3191 if((ratio.xRatio == 0 &&
3192 ratio.yStartRatio == 0 &&
3193 ratio.yEndRatio == 0) ||
3194 (devXRatio == ratio.xRatio &&
3195 devYRatio >= ratio.yStartRatio &&
3196 devYRatio <= ratio.yEndRatio))
3198 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3199 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3200 offset = GET_BE_WORD(tmp);
3201 break;
3205 if(offset == -1) {
3206 FIXME("No suitable ratio found\n");
3207 return ppem;
3210 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3211 USHORT recs;
3212 BYTE startsz, endsz;
3213 WORD *vTable;
3215 recs = GET_BE_WORD(group.recs);
3216 startsz = group.startsz;
3217 endsz = group.endsz;
3219 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3221 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3222 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3223 if(result == GDI_ERROR) {
3224 FIXME("Failed to retrieve vTable\n");
3225 goto end;
3228 if(height > 0) {
3229 for(i = 0; i < recs; i++) {
3230 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3231 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3232 ppem = GET_BE_WORD(vTable[i * 3]);
3234 if(yMax + -yMin == height) {
3235 font->yMax = yMax;
3236 font->yMin = yMin;
3237 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3238 break;
3240 if(yMax + -yMin > height) {
3241 if(--i < 0) {
3242 ppem = 0;
3243 goto end; /* failed */
3245 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3246 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3247 ppem = GET_BE_WORD(vTable[i * 3]);
3248 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3249 break;
3252 if(!font->yMax) {
3253 ppem = 0;
3254 TRACE("ppem not found for height %d\n", height);
3257 end:
3258 HeapFree(GetProcessHeap(), 0, vTable);
3261 return ppem;
3264 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3266 if(font->font_desc.hash != fd->hash) return TRUE;
3267 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3268 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3269 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3270 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3273 static void calc_hash(FONT_DESC *pfd)
3275 DWORD hash = 0, *ptr, two_chars;
3276 WORD *pwc;
3277 unsigned int i;
3279 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3280 hash ^= *ptr;
3281 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3282 hash ^= *ptr;
3283 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3284 two_chars = *ptr;
3285 pwc = (WCHAR *)&two_chars;
3286 if(!*pwc) break;
3287 *pwc = toupperW(*pwc);
3288 pwc++;
3289 *pwc = toupperW(*pwc);
3290 hash ^= two_chars;
3291 if(!*pwc) break;
3293 hash ^= !pfd->can_use_bitmap;
3294 pfd->hash = hash;
3295 return;
3298 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3300 GdiFont *ret;
3301 FONT_DESC fd;
3302 HFONTLIST *hflist;
3303 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3305 fd.lf = *plf;
3306 fd.matrix = *pmat;
3307 fd.can_use_bitmap = can_use_bitmap;
3308 calc_hash(&fd);
3310 /* try the child list */
3311 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3312 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3313 if(!fontcmp(ret, &fd)) {
3314 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3315 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3316 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3317 if(hflist->hfont == hfont)
3318 return ret;
3323 /* try the in-use list */
3324 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3325 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3326 if(!fontcmp(ret, &fd)) {
3327 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3328 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3329 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3330 if(hflist->hfont == hfont)
3331 return ret;
3333 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3334 hflist->hfont = hfont;
3335 list_add_head(&ret->hfontlist, &hflist->entry);
3336 return ret;
3340 /* then the unused list */
3341 font_elem_ptr = list_head(&unused_gdi_font_list);
3342 while(font_elem_ptr) {
3343 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3344 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3345 if(!fontcmp(ret, &fd)) {
3346 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3347 assert(list_empty(&ret->hfontlist));
3348 TRACE("Found %p in unused list\n", ret);
3349 list_remove(&ret->entry);
3350 list_add_head(&gdi_font_list, &ret->entry);
3351 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3352 hflist->hfont = hfont;
3353 list_add_head(&ret->hfontlist, &hflist->entry);
3354 return ret;
3357 return NULL;
3360 static void add_to_cache(GdiFont *font)
3362 static DWORD cache_num = 1;
3364 font->cache_num = cache_num++;
3365 list_add_head(&gdi_font_list, &font->entry);
3368 /*************************************************************
3369 * create_child_font_list
3371 static BOOL create_child_font_list(GdiFont *font)
3373 BOOL ret = FALSE;
3374 SYSTEM_LINKS *font_link;
3375 CHILD_FONT *font_link_entry, *new_child;
3376 FontSubst *psub;
3377 WCHAR* font_name;
3379 psub = get_font_subst(&font_subst_list, font->name, -1);
3380 font_name = psub ? psub->to.name : font->name;
3381 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3383 if(!strcmpiW(font_link->font_name, font_name))
3385 TRACE("found entry in system list\n");
3386 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3388 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3389 new_child->face = font_link_entry->face;
3390 new_child->font = NULL;
3391 list_add_tail(&font->child_fonts, &new_child->entry);
3392 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3394 ret = TRUE;
3395 break;
3399 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3400 * Sans Serif. This is how asian windows get default fallbacks for fonts
3402 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3403 font->charset != OEM_CHARSET &&
3404 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3405 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3407 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3409 TRACE("found entry in default fallback list\n");
3410 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3412 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3413 new_child->face = font_link_entry->face;
3414 new_child->font = NULL;
3415 list_add_tail(&font->child_fonts, &new_child->entry);
3416 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3418 ret = TRUE;
3419 break;
3423 return ret;
3426 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3428 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3430 if (pFT_Set_Charmap)
3432 FT_Int i;
3433 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3435 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3437 for (i = 0; i < ft_face->num_charmaps; i++)
3439 if (ft_face->charmaps[i]->encoding == encoding)
3441 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3442 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3444 switch (ft_face->charmaps[i]->platform_id)
3446 default:
3447 cmap_def = ft_face->charmaps[i];
3448 break;
3449 case 0: /* Apple Unicode */
3450 cmap0 = ft_face->charmaps[i];
3451 break;
3452 case 1: /* Macintosh */
3453 cmap1 = ft_face->charmaps[i];
3454 break;
3455 case 2: /* ISO */
3456 cmap2 = ft_face->charmaps[i];
3457 break;
3458 case 3: /* Microsoft */
3459 cmap3 = ft_face->charmaps[i];
3460 break;
3464 if (cmap3) /* prefer Microsoft cmap table */
3465 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3466 else if (cmap1)
3467 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3468 else if (cmap2)
3469 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3470 else if (cmap0)
3471 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3472 else if (cmap_def)
3473 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3475 return ft_err == FT_Err_Ok;
3478 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3481 /*************************************************************
3482 * WineEngCreateFontInstance
3485 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3487 GdiFont *ret;
3488 Face *face, *best, *best_bitmap;
3489 Family *family, *last_resort_family;
3490 struct list *family_elem_ptr, *face_elem_ptr;
3491 INT height, width = 0;
3492 unsigned int score = 0, new_score;
3493 signed int diff = 0, newdiff;
3494 BOOL bd, it, can_use_bitmap;
3495 LOGFONTW lf;
3496 CHARSETINFO csi;
3497 HFONTLIST *hflist;
3498 FMAT2 dcmat;
3499 FontSubst *psub = NULL;
3501 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3502 lf.lfWidth = abs(lf.lfWidth);
3504 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3506 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3507 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3508 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3509 lf.lfEscapement);
3511 if(dc->GraphicsMode == GM_ADVANCED)
3512 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3513 else
3515 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3516 font scaling abilities. */
3517 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3518 dcmat.eM21 = dcmat.eM12 = 0;
3521 /* Try to avoid not necessary glyph transformations */
3522 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3524 lf.lfHeight *= fabs(dcmat.eM11);
3525 lf.lfWidth *= fabs(dcmat.eM11);
3526 dcmat.eM11 = dcmat.eM22 = 1.0;
3529 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3530 dcmat.eM21, dcmat.eM22);
3532 GDI_CheckNotLock();
3533 EnterCriticalSection( &freetype_cs );
3535 /* check the cache first */
3536 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3537 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3538 LeaveCriticalSection( &freetype_cs );
3539 return ret;
3542 TRACE("not in cache\n");
3543 if(list_empty(&font_list)) /* No fonts installed */
3545 TRACE("No fonts installed\n");
3546 LeaveCriticalSection( &freetype_cs );
3547 return NULL;
3550 ret = alloc_font();
3552 ret->font_desc.matrix = dcmat;
3553 ret->font_desc.lf = lf;
3554 ret->font_desc.can_use_bitmap = can_use_bitmap;
3555 calc_hash(&ret->font_desc);
3556 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3557 hflist->hfont = hfont;
3558 list_add_head(&ret->hfontlist, &hflist->entry);
3560 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3561 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3562 original value lfCharSet. Note this is a special case for
3563 Symbol and doesn't happen at least for "Wingdings*" */
3565 if(!strcmpiW(lf.lfFaceName, SymbolW))
3566 lf.lfCharSet = SYMBOL_CHARSET;
3568 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3569 switch(lf.lfCharSet) {
3570 case DEFAULT_CHARSET:
3571 csi.fs.fsCsb[0] = 0;
3572 break;
3573 default:
3574 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3575 csi.fs.fsCsb[0] = 0;
3576 break;
3580 family = NULL;
3581 if(lf.lfFaceName[0] != '\0') {
3582 SYSTEM_LINKS *font_link;
3583 CHILD_FONT *font_link_entry;
3584 LPWSTR FaceName = lf.lfFaceName;
3587 * Check for a leading '@' this signals that the font is being
3588 * requested in tategaki mode (vertical writing substitution) but
3589 * does not affect the fontface that is to be selected.
3591 if (lf.lfFaceName[0]=='@')
3592 FaceName = &lf.lfFaceName[1];
3594 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3596 if(psub) {
3597 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3598 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3599 if (psub->to.charset != -1)
3600 lf.lfCharSet = psub->to.charset;
3603 /* We want a match on name and charset or just name if
3604 charset was DEFAULT_CHARSET. If the latter then
3605 we fixup the returned charset later in get_nearest_charset
3606 where we'll either use the charset of the current ansi codepage
3607 or if that's unavailable the first charset that the font supports.
3609 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3610 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3611 if (!strcmpiW(family->FamilyName, FaceName) ||
3612 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3614 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3615 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3616 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3617 if(face->scalable || can_use_bitmap)
3618 goto found;
3623 /* Search by full face name. */
3624 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3625 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3626 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3627 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3628 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3629 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3631 if(face->scalable || can_use_bitmap)
3632 goto found_face;
3638 * Try check the SystemLink list first for a replacement font.
3639 * We may find good replacements there.
3641 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3643 if(!strcmpiW(font_link->font_name, FaceName) ||
3644 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3646 TRACE("found entry in system list\n");
3647 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3649 face = font_link_entry->face;
3650 family = face->family;
3651 if(csi.fs.fsCsb[0] &
3652 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3654 if(face->scalable || can_use_bitmap)
3655 goto found;
3662 psub = NULL; /* substitution is no more relevant */
3664 /* If requested charset was DEFAULT_CHARSET then try using charset
3665 corresponding to the current ansi codepage */
3666 if (!csi.fs.fsCsb[0])
3668 INT acp = GetACP();
3669 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3670 FIXME("TCI failed on codepage %d\n", acp);
3671 csi.fs.fsCsb[0] = 0;
3672 } else
3673 lf.lfCharSet = csi.ciCharset;
3676 /* Face families are in the top 4 bits of lfPitchAndFamily,
3677 so mask with 0xF0 before testing */
3679 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3680 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3681 strcpyW(lf.lfFaceName, defFixed);
3682 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3683 strcpyW(lf.lfFaceName, defSerif);
3684 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3685 strcpyW(lf.lfFaceName, defSans);
3686 else
3687 strcpyW(lf.lfFaceName, defSans);
3688 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3689 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3690 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3691 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3692 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3693 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3694 if(face->scalable || can_use_bitmap)
3695 goto found;
3700 last_resort_family = NULL;
3701 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3702 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3703 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3704 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3705 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3706 if(face->scalable)
3707 goto found;
3708 if(can_use_bitmap && !last_resort_family)
3709 last_resort_family = family;
3714 if(last_resort_family) {
3715 family = last_resort_family;
3716 csi.fs.fsCsb[0] = 0;
3717 goto found;
3720 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3721 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3722 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3723 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3724 if(face->scalable) {
3725 csi.fs.fsCsb[0] = 0;
3726 WARN("just using first face for now\n");
3727 goto found;
3729 if(can_use_bitmap && !last_resort_family)
3730 last_resort_family = family;
3733 if(!last_resort_family) {
3734 FIXME("can't find a single appropriate font - bailing\n");
3735 free_font(ret);
3736 LeaveCriticalSection( &freetype_cs );
3737 return NULL;
3740 WARN("could only find a bitmap font - this will probably look awful!\n");
3741 family = last_resort_family;
3742 csi.fs.fsCsb[0] = 0;
3744 found:
3745 it = lf.lfItalic ? 1 : 0;
3746 bd = lf.lfWeight > 550 ? 1 : 0;
3748 height = lf.lfHeight;
3750 face = best = best_bitmap = NULL;
3751 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3753 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3755 BOOL italic, bold;
3757 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3758 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3759 new_score = (italic ^ it) + (bold ^ bd);
3760 if(!best || new_score <= score)
3762 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3763 italic, bold, it, bd);
3764 score = new_score;
3765 best = face;
3766 if(best->scalable && score == 0) break;
3767 if(!best->scalable)
3769 if(height > 0)
3770 newdiff = height - (signed int)(best->size.height);
3771 else
3772 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3773 if(!best_bitmap || new_score < score ||
3774 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3776 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3777 diff = newdiff;
3778 best_bitmap = best;
3779 if(score == 0 && diff == 0) break;
3785 if(best)
3786 face = best->scalable ? best : best_bitmap;
3787 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3788 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3790 found_face:
3791 height = lf.lfHeight;
3793 ret->fs = face->fs;
3795 if(csi.fs.fsCsb[0]) {
3796 ret->charset = lf.lfCharSet;
3797 ret->codepage = csi.ciACP;
3799 else
3800 ret->charset = get_nearest_charset(face, &ret->codepage);
3802 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3803 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3805 ret->aveWidth = height ? lf.lfWidth : 0;
3807 if(!face->scalable) {
3808 /* Windows uses integer scaling factors for bitmap fonts */
3809 INT scale, scaled_height;
3810 GdiFont *cachedfont;
3812 /* FIXME: rotation of bitmap fonts is ignored */
3813 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3814 if (ret->aveWidth)
3815 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3816 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3817 dcmat.eM11 = dcmat.eM22 = 1.0;
3818 /* As we changed the matrix, we need to search the cache for the font again,
3819 * otherwise we might explode the cache. */
3820 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3821 TRACE("Found cached font after non-scalable matrix rescale!\n");
3822 free_font( ret );
3823 LeaveCriticalSection( &freetype_cs );
3824 return cachedfont;
3826 calc_hash(&ret->font_desc);
3828 if (height != 0) height = diff;
3829 height += face->size.height;
3831 scale = (height + face->size.height - 1) / face->size.height;
3832 scaled_height = scale * face->size.height;
3833 /* Only jump to the next height if the difference <= 25% original height */
3834 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3835 /* The jump between unscaled and doubled is delayed by 1 */
3836 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3837 ret->scale_y = scale;
3839 width = face->size.x_ppem >> 6;
3840 height = face->size.y_ppem >> 6;
3842 else
3843 ret->scale_y = 1.0;
3844 TRACE("font scale y: %f\n", ret->scale_y);
3846 ret->ft_face = OpenFontFace(ret, face, width, height);
3848 if (!ret->ft_face)
3850 free_font( ret );
3851 LeaveCriticalSection( &freetype_cs );
3852 return 0;
3855 ret->ntmFlags = face->ntmFlags;
3857 if (ret->charset == SYMBOL_CHARSET &&
3858 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3859 /* No ops */
3861 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3862 /* No ops */
3864 else {
3865 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3868 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3869 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3870 ret->underline = lf.lfUnderline ? 0xff : 0;
3871 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3872 create_child_font_list(ret);
3874 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3876 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3877 if (length != GDI_ERROR)
3879 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3880 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3881 TRACE("Loaded GSUB table of %i bytes\n",length);
3885 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3887 add_to_cache(ret);
3888 LeaveCriticalSection( &freetype_cs );
3889 return ret;
3892 static void dump_gdi_font_list(void)
3894 GdiFont *gdiFont;
3895 struct list *elem_ptr;
3897 TRACE("---------- gdiFont Cache ----------\n");
3898 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3899 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3900 TRACE("gdiFont=%p %s %d\n",
3901 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3904 TRACE("---------- Unused gdiFont Cache ----------\n");
3905 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3906 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3907 TRACE("gdiFont=%p %s %d\n",
3908 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3911 TRACE("---------- Child gdiFont Cache ----------\n");
3912 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3913 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3914 TRACE("gdiFont=%p %s %d\n",
3915 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3919 /*************************************************************
3920 * WineEngDestroyFontInstance
3922 * free the gdiFont associated with this handle
3925 BOOL WineEngDestroyFontInstance(HFONT handle)
3927 GdiFont *gdiFont;
3928 HFONTLIST *hflist;
3929 BOOL ret = FALSE;
3930 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3931 int i = 0;
3933 GDI_CheckNotLock();
3934 EnterCriticalSection( &freetype_cs );
3936 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3938 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3939 while(hfontlist_elem_ptr) {
3940 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3941 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3942 if(hflist->hfont == handle) {
3943 TRACE("removing child font %p from child list\n", gdiFont);
3944 list_remove(&gdiFont->entry);
3945 LeaveCriticalSection( &freetype_cs );
3946 return TRUE;
3951 TRACE("destroying hfont=%p\n", handle);
3952 if(TRACE_ON(font))
3953 dump_gdi_font_list();
3955 font_elem_ptr = list_head(&gdi_font_list);
3956 while(font_elem_ptr) {
3957 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3958 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3960 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3961 while(hfontlist_elem_ptr) {
3962 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3963 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3964 if(hflist->hfont == handle) {
3965 list_remove(&hflist->entry);
3966 HeapFree(GetProcessHeap(), 0, hflist);
3967 ret = TRUE;
3970 if(list_empty(&gdiFont->hfontlist)) {
3971 TRACE("Moving to Unused list\n");
3972 list_remove(&gdiFont->entry);
3973 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3978 font_elem_ptr = list_head(&unused_gdi_font_list);
3979 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3980 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3981 while(font_elem_ptr) {
3982 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3983 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3984 TRACE("freeing %p\n", gdiFont);
3985 list_remove(&gdiFont->entry);
3986 free_font(gdiFont);
3988 LeaveCriticalSection( &freetype_cs );
3989 return ret;
3992 /***************************************************
3993 * create_enum_charset_list
3995 * This function creates charset enumeration list because in DEFAULT_CHARSET
3996 * case, the ANSI codepage's charset takes precedence over other charsets.
3997 * This function works as a filter other than DEFAULT_CHARSET case.
3999 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4001 CHARSETINFO csi;
4002 DWORD n = 0;
4004 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4005 csi.fs.fsCsb[0] != 0) {
4006 list->element[n].mask = csi.fs.fsCsb[0];
4007 list->element[n].charset = csi.ciCharset;
4008 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4009 n++;
4011 else { /* charset is DEFAULT_CHARSET or invalid. */
4012 INT acp, i;
4014 /* Set the current codepage's charset as the first element. */
4015 acp = GetACP();
4016 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4017 csi.fs.fsCsb[0] != 0) {
4018 list->element[n].mask = csi.fs.fsCsb[0];
4019 list->element[n].charset = csi.ciCharset;
4020 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4021 n++;
4024 /* Fill out left elements. */
4025 for (i = 0; i < 32; i++) {
4026 FONTSIGNATURE fs;
4027 fs.fsCsb[0] = 1L << i;
4028 fs.fsCsb[1] = 0;
4029 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4030 continue; /* skip, already added. */
4031 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4032 continue; /* skip, this is an invalid fsCsb bit. */
4034 list->element[n].mask = fs.fsCsb[0];
4035 list->element[n].charset = csi.ciCharset;
4036 list->element[n].name = ElfScriptsW[i];
4037 n++;
4040 list->total = n;
4042 return n;
4045 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4046 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4048 GdiFont *font;
4049 LONG width, height;
4051 if (face->cached_enum_data)
4053 TRACE("Cached\n");
4054 *pelf = face->cached_enum_data->elf;
4055 *pntm = face->cached_enum_data->ntm;
4056 *ptype = face->cached_enum_data->type;
4057 return;
4060 font = alloc_font();
4062 if(face->scalable) {
4063 height = -2048; /* 2048 is the most common em size */
4064 width = 0;
4065 } else {
4066 height = face->size.y_ppem >> 6;
4067 width = face->size.x_ppem >> 6;
4069 font->scale_y = 1.0;
4071 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4073 free_font(font);
4074 return;
4077 font->name = strdupW(face->family->FamilyName);
4078 font->ntmFlags = face->ntmFlags;
4080 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4082 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4084 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4086 lstrcpynW(pelf->elfLogFont.lfFaceName,
4087 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4088 LF_FACESIZE);
4089 lstrcpynW(pelf->elfFullName,
4090 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4091 LF_FULLFACESIZE);
4092 lstrcpynW(pelf->elfStyle,
4093 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4094 LF_FACESIZE);
4096 else
4098 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4100 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4102 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4103 if (face->FullName)
4104 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4105 else
4106 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4107 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4110 pntm->ntmTm.ntmFlags = face->ntmFlags;
4111 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4112 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4113 pntm->ntmFontSig = face->fs;
4115 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4117 pelf->elfLogFont.lfEscapement = 0;
4118 pelf->elfLogFont.lfOrientation = 0;
4119 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4120 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4121 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4122 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4123 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4124 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4125 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4126 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4127 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4128 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4129 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4131 *ptype = 0;
4132 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4133 *ptype |= TRUETYPE_FONTTYPE;
4134 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4135 *ptype |= DEVICE_FONTTYPE;
4136 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4137 *ptype |= RASTER_FONTTYPE;
4139 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4140 if (face->cached_enum_data)
4142 face->cached_enum_data->elf = *pelf;
4143 face->cached_enum_data->ntm = *pntm;
4144 face->cached_enum_data->type = *ptype;
4147 free_font(font);
4150 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4152 struct list *face_elem_ptr;
4154 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4156 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4158 static const WCHAR spaceW[] = { ' ',0 };
4159 WCHAR full_family_name[LF_FULLFACESIZE];
4160 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4162 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4164 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4165 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4166 continue;
4169 strcpyW(full_family_name, family->FamilyName);
4170 strcatW(full_family_name, spaceW);
4171 strcatW(full_family_name, face->StyleName);
4172 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4175 return FALSE;
4178 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4180 static const WCHAR spaceW[] = { ' ',0 };
4181 WCHAR full_family_name[LF_FULLFACESIZE];
4183 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4185 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4187 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4188 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4189 return FALSE;
4192 strcpyW(full_family_name, face->family->FamilyName);
4193 strcatW(full_family_name, spaceW);
4194 strcatW(full_family_name, face->StyleName);
4195 return !strcmpiW(lf->lfFaceName, full_family_name);
4198 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4199 FONTENUMPROCW proc, LPARAM lparam)
4201 ENUMLOGFONTEXW elf;
4202 NEWTEXTMETRICEXW ntm;
4203 DWORD type = 0;
4204 int i;
4206 GetEnumStructs(face, &elf, &ntm, &type);
4207 for(i = 0; i < list->total; i++) {
4208 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4209 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4210 strcpyW(elf.elfScript, OEM_DOSW);
4211 i = 32; /* break out of loop */
4212 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4213 continue;
4214 else {
4215 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4216 if(list->element[i].name)
4217 strcpyW(elf.elfScript, list->element[i].name);
4218 else
4219 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4221 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4222 debugstr_w(elf.elfLogFont.lfFaceName),
4223 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4224 list->element[i].charset, type, debugstr_w(elf.elfScript),
4225 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4226 ntm.ntmTm.ntmFlags);
4227 /* release section before callback (FIXME) */
4228 LeaveCriticalSection( &freetype_cs );
4229 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4230 EnterCriticalSection( &freetype_cs );
4232 return TRUE;
4235 /*************************************************************
4236 * WineEngEnumFonts
4239 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4241 Family *family;
4242 Face *face;
4243 struct list *family_elem_ptr, *face_elem_ptr;
4244 LOGFONTW lf;
4245 struct enum_charset_list enum_charsets;
4247 if (!plf)
4249 lf.lfCharSet = DEFAULT_CHARSET;
4250 lf.lfPitchAndFamily = 0;
4251 lf.lfFaceName[0] = 0;
4252 plf = &lf;
4255 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4257 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4259 GDI_CheckNotLock();
4260 EnterCriticalSection( &freetype_cs );
4261 if(plf->lfFaceName[0]) {
4262 FontSubst *psub;
4263 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4265 if(psub) {
4266 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4267 debugstr_w(psub->to.name));
4268 lf = *plf;
4269 strcpyW(lf.lfFaceName, psub->to.name);
4270 plf = &lf;
4273 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4274 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4275 if(family_matches(family, plf)) {
4276 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4277 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4278 if (!face_matches(face, plf)) continue;
4279 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4283 } else {
4284 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4285 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4286 face_elem_ptr = list_head(&family->faces);
4287 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4288 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4291 LeaveCriticalSection( &freetype_cs );
4292 return 1;
4295 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4297 pt->x.value = vec->x >> 6;
4298 pt->x.fract = (vec->x & 0x3f) << 10;
4299 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4300 pt->y.value = vec->y >> 6;
4301 pt->y.fract = (vec->y & 0x3f) << 10;
4302 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4303 return;
4306 /***************************************************
4307 * According to the MSDN documentation on WideCharToMultiByte,
4308 * certain codepages cannot set the default_used parameter.
4309 * This returns TRUE if the codepage can set that parameter, false else
4310 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4312 static BOOL codepage_sets_default_used(UINT codepage)
4314 switch (codepage)
4316 case CP_UTF7:
4317 case CP_UTF8:
4318 case CP_SYMBOL:
4319 return FALSE;
4320 default:
4321 return TRUE;
4326 * GSUB Table handling functions
4329 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4331 const GSUB_CoverageFormat1* cf1;
4333 cf1 = table;
4335 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4337 int count = GET_BE_WORD(cf1->GlyphCount);
4338 int i;
4339 TRACE("Coverage Format 1, %i glyphs\n",count);
4340 for (i = 0; i < count; i++)
4341 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4342 return i;
4343 return -1;
4345 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4347 const GSUB_CoverageFormat2* cf2;
4348 int i;
4349 int count;
4350 cf2 = (const GSUB_CoverageFormat2*)cf1;
4352 count = GET_BE_WORD(cf2->RangeCount);
4353 TRACE("Coverage Format 2, %i ranges\n",count);
4354 for (i = 0; i < count; i++)
4356 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4357 return -1;
4358 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4359 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4361 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4362 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4365 return -1;
4367 else
4368 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4370 return -1;
4373 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4375 const GSUB_ScriptList *script;
4376 const GSUB_Script *deflt = NULL;
4377 int i;
4378 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4380 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4381 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4383 const GSUB_Script *scr;
4384 int offset;
4386 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4387 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4389 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4390 return scr;
4391 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4392 deflt = scr;
4394 return deflt;
4397 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4399 int i;
4400 int offset;
4401 const GSUB_LangSys *Lang;
4403 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4405 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4407 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4408 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4410 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4411 return Lang;
4413 offset = GET_BE_WORD(script->DefaultLangSys);
4414 if (offset)
4416 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4417 return Lang;
4419 return NULL;
4422 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4424 int i;
4425 const GSUB_FeatureList *feature;
4426 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4428 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4429 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4431 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4432 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4434 const GSUB_Feature *feat;
4435 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4436 return feat;
4439 return NULL;
4442 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4444 int i;
4445 int offset;
4446 const GSUB_LookupList *lookup;
4447 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4449 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4450 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4452 const GSUB_LookupTable *look;
4453 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4454 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4455 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4456 if (GET_BE_WORD(look->LookupType) != 1)
4457 FIXME("We only handle SubType 1\n");
4458 else
4460 int j;
4462 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4464 const GSUB_SingleSubstFormat1 *ssf1;
4465 offset = GET_BE_WORD(look->SubTable[j]);
4466 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4467 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4469 int offset = GET_BE_WORD(ssf1->Coverage);
4470 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4471 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4473 TRACE(" Glyph 0x%x ->",glyph);
4474 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4475 TRACE(" 0x%x\n",glyph);
4478 else
4480 const GSUB_SingleSubstFormat2 *ssf2;
4481 INT index;
4482 INT offset;
4484 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4485 offset = GET_BE_WORD(ssf1->Coverage);
4486 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4487 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4488 TRACE(" Coverage index %i\n",index);
4489 if (index != -1)
4491 TRACE(" Glyph is 0x%x ->",glyph);
4492 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4493 TRACE("0x%x\n",glyph);
4499 return glyph;
4502 static const char* get_opentype_script(const GdiFont *font)
4505 * I am not sure if this is the correct way to generate our script tag
4508 switch (font->charset)
4510 case ANSI_CHARSET: return "latn";
4511 case BALTIC_CHARSET: return "latn"; /* ?? */
4512 case CHINESEBIG5_CHARSET: return "hani";
4513 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4514 case GB2312_CHARSET: return "hani";
4515 case GREEK_CHARSET: return "grek";
4516 case HANGUL_CHARSET: return "hang";
4517 case RUSSIAN_CHARSET: return "cyrl";
4518 case SHIFTJIS_CHARSET: return "kana";
4519 case TURKISH_CHARSET: return "latn"; /* ?? */
4520 case VIETNAMESE_CHARSET: return "latn";
4521 case JOHAB_CHARSET: return "latn"; /* ?? */
4522 case ARABIC_CHARSET: return "arab";
4523 case HEBREW_CHARSET: return "hebr";
4524 case THAI_CHARSET: return "thai";
4525 default: return "latn";
4529 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4531 const GSUB_Header *header;
4532 const GSUB_Script *script;
4533 const GSUB_LangSys *language;
4534 const GSUB_Feature *feature;
4536 if (!font->GSUB_Table)
4537 return glyph;
4539 header = font->GSUB_Table;
4541 script = GSUB_get_script_table(header, get_opentype_script(font));
4542 if (!script)
4544 TRACE("Script not found\n");
4545 return glyph;
4547 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4548 if (!language)
4550 TRACE("Language not found\n");
4551 return glyph;
4553 feature = GSUB_get_feature(header, language, "vrt2");
4554 if (!feature)
4555 feature = GSUB_get_feature(header, language, "vert");
4556 if (!feature)
4558 TRACE("vrt2/vert feature not found\n");
4559 return glyph;
4561 return GSUB_apply_feature(header, feature, glyph);
4564 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4566 FT_UInt glyphId;
4568 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4569 WCHAR wc = (WCHAR)glyph;
4570 BOOL default_used;
4571 BOOL *default_used_pointer;
4572 FT_UInt ret;
4573 char buf;
4574 default_used_pointer = NULL;
4575 default_used = FALSE;
4576 if (codepage_sets_default_used(font->codepage))
4577 default_used_pointer = &default_used;
4578 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4579 ret = 0;
4580 else
4581 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4582 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4583 return get_GSUB_vert_glyph(font,ret);
4586 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4588 if (glyph < 0x100) glyph += 0xf000;
4589 /* there is a number of old pre-Unicode "broken" TTFs, which
4590 do have symbols at U+00XX instead of U+f0XX */
4591 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4592 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4594 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4596 return get_GSUB_vert_glyph(font,glyphId);
4599 /*************************************************************
4600 * WineEngGetGlyphIndices
4603 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4604 LPWORD pgi, DWORD flags)
4606 int i;
4607 WORD default_char;
4608 BOOL got_default = FALSE;
4610 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4612 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4613 got_default = TRUE;
4616 for(i = 0; i < count; i++)
4618 pgi[i] = get_glyph_index(font, lpstr[i]);
4619 if (pgi[i] == 0)
4621 if (!got_default)
4623 if (FT_IS_SFNT(font->ft_face))
4625 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4626 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4628 else
4630 TEXTMETRICW textm;
4631 WineEngGetTextMetrics(font, &textm);
4632 default_char = textm.tmDefaultChar;
4634 got_default = TRUE;
4636 pgi[i] = default_char;
4639 return count;
4642 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4644 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4645 return !memcmp(matrix, &identity, sizeof(FMAT2));
4648 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4650 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4651 return !memcmp(matrix, &identity, sizeof(MAT2));
4654 /*************************************************************
4655 * WineEngGetGlyphOutline
4657 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4658 * except that the first parameter is the HWINEENGFONT of the font in
4659 * question rather than an HDC.
4662 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4663 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4664 const MAT2* lpmat)
4666 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4667 FT_Face ft_face = incoming_font->ft_face;
4668 GdiFont *font = incoming_font;
4669 FT_UInt glyph_index;
4670 DWORD width, height, pitch, needed = 0;
4671 FT_Bitmap ft_bitmap;
4672 FT_Error err;
4673 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4674 FT_Angle angle = 0;
4675 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4676 double widthRatio = 1.0;
4677 FT_Matrix transMat = identityMat;
4678 FT_Matrix transMatUnrotated;
4679 BOOL needsTransform = FALSE;
4680 BOOL tategaki = (font->GSUB_Table != NULL);
4681 UINT original_index;
4683 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4684 buflen, buf, lpmat);
4686 TRACE("font transform %f %f %f %f\n",
4687 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4688 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4690 GDI_CheckNotLock();
4691 EnterCriticalSection( &freetype_cs );
4693 if(format & GGO_GLYPH_INDEX) {
4694 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4695 original_index = glyph;
4696 format &= ~GGO_GLYPH_INDEX;
4697 } else {
4698 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4699 ft_face = font->ft_face;
4700 original_index = glyph_index;
4703 if(format & GGO_UNHINTED) {
4704 load_flags |= FT_LOAD_NO_HINTING;
4705 format &= ~GGO_UNHINTED;
4708 /* tategaki never appears to happen to lower glyph index */
4709 if (glyph_index < TATEGAKI_LOWER_BOUND )
4710 tategaki = FALSE;
4712 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4713 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4714 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4715 font->gmsize * sizeof(GM*));
4716 } else {
4717 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4718 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4720 *lpgm = FONT_GM(font,original_index)->gm;
4721 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4722 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4723 lpgm->gmCellIncX, lpgm->gmCellIncY);
4724 LeaveCriticalSection( &freetype_cs );
4725 return 1; /* FIXME */
4729 if (!font->gm[original_index / GM_BLOCK_SIZE])
4730 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4732 /* Scaling factor */
4733 if (font->aveWidth)
4735 TEXTMETRICW tm;
4737 WineEngGetTextMetrics(font, &tm);
4739 widthRatio = (double)font->aveWidth;
4740 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4742 else
4743 widthRatio = font->scale_y;
4745 /* Scaling transform */
4746 if (widthRatio != 1.0 || font->scale_y != 1.0)
4748 FT_Matrix scaleMat;
4749 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4750 scaleMat.xy = 0;
4751 scaleMat.yx = 0;
4752 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4754 pFT_Matrix_Multiply(&scaleMat, &transMat);
4755 needsTransform = TRUE;
4758 /* Slant transform */
4759 if (font->fake_italic) {
4760 FT_Matrix slantMat;
4762 slantMat.xx = (1 << 16);
4763 slantMat.xy = ((1 << 16) >> 2);
4764 slantMat.yx = 0;
4765 slantMat.yy = (1 << 16);
4766 pFT_Matrix_Multiply(&slantMat, &transMat);
4767 needsTransform = TRUE;
4770 /* Rotation transform */
4771 transMatUnrotated = transMat;
4772 if(font->orientation && !tategaki) {
4773 FT_Matrix rotationMat;
4774 FT_Vector vecAngle;
4775 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4776 pFT_Vector_Unit(&vecAngle, angle);
4777 rotationMat.xx = vecAngle.x;
4778 rotationMat.xy = -vecAngle.y;
4779 rotationMat.yx = -rotationMat.xy;
4780 rotationMat.yy = rotationMat.xx;
4782 pFT_Matrix_Multiply(&rotationMat, &transMat);
4783 needsTransform = TRUE;
4786 /* World transform */
4787 if (!is_identity_FMAT2(&font->font_desc.matrix))
4789 FT_Matrix worldMat;
4790 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4791 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4792 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4793 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4794 pFT_Matrix_Multiply(&worldMat, &transMat);
4795 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4796 needsTransform = TRUE;
4799 /* Extra transformation specified by caller */
4800 if (!is_identity_MAT2(lpmat))
4802 FT_Matrix extraMat;
4803 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4804 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4805 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4806 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4807 pFT_Matrix_Multiply(&extraMat, &transMat);
4808 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4809 needsTransform = TRUE;
4812 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4813 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4814 format == GGO_GRAY8_BITMAP))
4816 load_flags |= FT_LOAD_NO_BITMAP;
4819 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4821 if(err) {
4822 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4823 LeaveCriticalSection( &freetype_cs );
4824 return GDI_ERROR;
4827 if(!needsTransform) {
4828 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4829 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4830 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4832 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4833 bottom = (ft_face->glyph->metrics.horiBearingY -
4834 ft_face->glyph->metrics.height) & -64;
4835 lpgm->gmCellIncX = adv;
4836 lpgm->gmCellIncY = 0;
4837 } else {
4838 INT xc, yc;
4839 FT_Vector vec;
4841 left = right = 0;
4843 for(xc = 0; xc < 2; xc++) {
4844 for(yc = 0; yc < 2; yc++) {
4845 vec.x = (ft_face->glyph->metrics.horiBearingX +
4846 xc * ft_face->glyph->metrics.width);
4847 vec.y = ft_face->glyph->metrics.horiBearingY -
4848 yc * ft_face->glyph->metrics.height;
4849 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4850 pFT_Vector_Transform(&vec, &transMat);
4851 if(xc == 0 && yc == 0) {
4852 left = right = vec.x;
4853 top = bottom = vec.y;
4854 } else {
4855 if(vec.x < left) left = vec.x;
4856 else if(vec.x > right) right = vec.x;
4857 if(vec.y < bottom) bottom = vec.y;
4858 else if(vec.y > top) top = vec.y;
4862 left = left & -64;
4863 right = (right + 63) & -64;
4864 bottom = bottom & -64;
4865 top = (top + 63) & -64;
4867 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4868 vec.x = ft_face->glyph->metrics.horiAdvance;
4869 vec.y = 0;
4870 pFT_Vector_Transform(&vec, &transMat);
4871 lpgm->gmCellIncX = (vec.x+63) >> 6;
4872 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4874 vec.x = ft_face->glyph->metrics.horiAdvance;
4875 vec.y = 0;
4876 pFT_Vector_Transform(&vec, &transMatUnrotated);
4877 adv = (vec.x+63) >> 6;
4880 lsb = left >> 6;
4881 bbx = (right - left) >> 6;
4882 lpgm->gmBlackBoxX = (right - left) >> 6;
4883 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4884 lpgm->gmptGlyphOrigin.x = left >> 6;
4885 lpgm->gmptGlyphOrigin.y = top >> 6;
4887 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4888 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4889 lpgm->gmCellIncX, lpgm->gmCellIncY);
4891 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4892 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4894 FONT_GM(font,original_index)->gm = *lpgm;
4895 FONT_GM(font,original_index)->adv = adv;
4896 FONT_GM(font,original_index)->lsb = lsb;
4897 FONT_GM(font,original_index)->bbx = bbx;
4898 FONT_GM(font,original_index)->init = TRUE;
4901 if(format == GGO_METRICS)
4903 LeaveCriticalSection( &freetype_cs );
4904 return 1; /* FIXME */
4907 if(ft_face->glyph->format != ft_glyph_format_outline &&
4908 (format == GGO_NATIVE || format == GGO_BEZIER ||
4909 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4910 format == GGO_GRAY8_BITMAP))
4912 TRACE("loaded a bitmap\n");
4913 LeaveCriticalSection( &freetype_cs );
4914 return GDI_ERROR;
4917 switch(format) {
4918 case GGO_BITMAP:
4919 width = lpgm->gmBlackBoxX;
4920 height = lpgm->gmBlackBoxY;
4921 pitch = ((width + 31) >> 5) << 2;
4922 needed = pitch * height;
4924 if(!buf || !buflen) break;
4926 switch(ft_face->glyph->format) {
4927 case ft_glyph_format_bitmap:
4929 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4930 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4931 INT h = ft_face->glyph->bitmap.rows;
4932 while(h--) {
4933 memcpy(dst, src, w);
4934 src += ft_face->glyph->bitmap.pitch;
4935 dst += pitch;
4937 break;
4940 case ft_glyph_format_outline:
4941 ft_bitmap.width = width;
4942 ft_bitmap.rows = height;
4943 ft_bitmap.pitch = pitch;
4944 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4945 ft_bitmap.buffer = buf;
4947 if(needsTransform)
4948 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4950 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4952 /* Note: FreeType will only set 'black' bits for us. */
4953 memset(buf, 0, needed);
4954 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4955 break;
4957 default:
4958 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4959 LeaveCriticalSection( &freetype_cs );
4960 return GDI_ERROR;
4962 break;
4964 case GGO_GRAY2_BITMAP:
4965 case GGO_GRAY4_BITMAP:
4966 case GGO_GRAY8_BITMAP:
4967 case WINE_GGO_GRAY16_BITMAP:
4969 unsigned int mult, row, col;
4970 BYTE *start, *ptr;
4972 width = lpgm->gmBlackBoxX;
4973 height = lpgm->gmBlackBoxY;
4974 pitch = (width + 3) / 4 * 4;
4975 needed = pitch * height;
4977 if(!buf || !buflen) break;
4979 switch(ft_face->glyph->format) {
4980 case ft_glyph_format_bitmap:
4982 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4983 INT h = ft_face->glyph->bitmap.rows;
4984 INT x;
4985 memset( buf, 0, needed );
4986 while(h--) {
4987 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4988 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4989 src += ft_face->glyph->bitmap.pitch;
4990 dst += pitch;
4992 LeaveCriticalSection( &freetype_cs );
4993 return needed;
4995 case ft_glyph_format_outline:
4997 ft_bitmap.width = width;
4998 ft_bitmap.rows = height;
4999 ft_bitmap.pitch = pitch;
5000 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5001 ft_bitmap.buffer = buf;
5003 if(needsTransform)
5004 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5006 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5008 memset(ft_bitmap.buffer, 0, buflen);
5010 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5012 if(format == GGO_GRAY2_BITMAP)
5013 mult = 4;
5014 else if(format == GGO_GRAY4_BITMAP)
5015 mult = 16;
5016 else if(format == GGO_GRAY8_BITMAP)
5017 mult = 64;
5018 else /* format == WINE_GGO_GRAY16_BITMAP */
5020 LeaveCriticalSection( &freetype_cs );
5021 return needed;
5023 break;
5025 default:
5026 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5027 LeaveCriticalSection( &freetype_cs );
5028 return GDI_ERROR;
5031 start = buf;
5032 for(row = 0; row < height; row++) {
5033 ptr = start;
5034 for(col = 0; col < width; col++, ptr++) {
5035 *ptr = (((int)*ptr) * mult + 128) / 256;
5037 start += pitch;
5039 break;
5042 case WINE_GGO_HRGB_BITMAP:
5043 case WINE_GGO_HBGR_BITMAP:
5044 case WINE_GGO_VRGB_BITMAP:
5045 case WINE_GGO_VBGR_BITMAP:
5046 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5048 switch (ft_face->glyph->format)
5050 case FT_GLYPH_FORMAT_BITMAP:
5052 BYTE *src, *dst;
5053 INT src_pitch, x;
5055 width = lpgm->gmBlackBoxX;
5056 height = lpgm->gmBlackBoxY;
5057 pitch = width * 4;
5058 needed = pitch * height;
5060 if (!buf || !buflen) break;
5062 memset(buf, 0, buflen);
5063 dst = buf;
5064 src = ft_face->glyph->bitmap.buffer;
5065 src_pitch = ft_face->glyph->bitmap.pitch;
5067 height = min( height, ft_face->glyph->bitmap.rows );
5068 while ( height-- )
5070 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5072 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5073 ((unsigned int *)dst)[x] = ~0u;
5075 src += src_pitch;
5076 dst += pitch;
5079 break;
5082 case FT_GLYPH_FORMAT_OUTLINE:
5084 unsigned int *dst;
5085 BYTE *src;
5086 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5087 INT x_shift, y_shift;
5088 BOOL rgb;
5089 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5090 FT_Render_Mode render_mode =
5091 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5092 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5094 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5096 if ( render_mode == FT_RENDER_MODE_LCD)
5098 lpgm->gmBlackBoxX += 2;
5099 lpgm->gmptGlyphOrigin.x -= 1;
5101 else
5103 lpgm->gmBlackBoxY += 2;
5104 lpgm->gmptGlyphOrigin.y += 1;
5108 width = lpgm->gmBlackBoxX;
5109 height = lpgm->gmBlackBoxY;
5110 pitch = width * 4;
5111 needed = pitch * height;
5113 if (!buf || !buflen) break;
5115 memset(buf, 0, buflen);
5116 dst = buf;
5117 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5119 if ( needsTransform )
5120 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5122 if ( pFT_Library_SetLcdFilter )
5123 pFT_Library_SetLcdFilter( library, lcdfilter );
5124 pFT_Render_Glyph (ft_face->glyph, render_mode);
5126 src = ft_face->glyph->bitmap.buffer;
5127 src_pitch = ft_face->glyph->bitmap.pitch;
5128 src_width = ft_face->glyph->bitmap.width;
5129 src_height = ft_face->glyph->bitmap.rows;
5131 if ( render_mode == FT_RENDER_MODE_LCD)
5133 rgb_interval = 1;
5134 hmul = 3;
5135 vmul = 1;
5137 else
5139 rgb_interval = src_pitch;
5140 hmul = 1;
5141 vmul = 3;
5144 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5145 if ( x_shift < 0 ) x_shift = 0;
5146 if ( x_shift + (src_width / hmul) > width )
5147 x_shift = width - (src_width / hmul);
5149 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5150 if ( y_shift < 0 ) y_shift = 0;
5151 if ( y_shift + (src_height / vmul) > height )
5152 y_shift = height - (src_height / vmul);
5154 dst += x_shift + y_shift * ( pitch / 4 );
5155 while ( src_height )
5157 for ( x = 0; x < src_width / hmul; x++ )
5159 if ( rgb )
5161 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5162 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5163 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5164 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5166 else
5168 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5169 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5170 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5171 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5174 src += src_pitch * vmul;
5175 dst += pitch / 4;
5176 src_height -= vmul;
5179 break;
5182 default:
5183 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5184 LeaveCriticalSection ( &freetype_cs );
5185 return GDI_ERROR;
5188 break;
5190 #else
5191 LeaveCriticalSection( &freetype_cs );
5192 return GDI_ERROR;
5193 #endif
5195 case GGO_NATIVE:
5197 int contour, point = 0, first_pt;
5198 FT_Outline *outline = &ft_face->glyph->outline;
5199 TTPOLYGONHEADER *pph;
5200 TTPOLYCURVE *ppc;
5201 DWORD pph_start, cpfx, type;
5203 if(buflen == 0) buf = NULL;
5205 if (needsTransform && buf) {
5206 pFT_Outline_Transform(outline, &transMat);
5209 for(contour = 0; contour < outline->n_contours; contour++) {
5210 pph_start = needed;
5211 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5212 first_pt = point;
5213 if(buf) {
5214 pph->dwType = TT_POLYGON_TYPE;
5215 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5217 needed += sizeof(*pph);
5218 point++;
5219 while(point <= outline->contours[contour]) {
5220 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5221 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5222 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5223 cpfx = 0;
5224 do {
5225 if(buf)
5226 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5227 cpfx++;
5228 point++;
5229 } while(point <= outline->contours[contour] &&
5230 (outline->tags[point] & FT_Curve_Tag_On) ==
5231 (outline->tags[point-1] & FT_Curve_Tag_On));
5232 /* At the end of a contour Windows adds the start point, but
5233 only for Beziers */
5234 if(point > outline->contours[contour] &&
5235 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5236 if(buf)
5237 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5238 cpfx++;
5239 } else if(point <= outline->contours[contour] &&
5240 outline->tags[point] & FT_Curve_Tag_On) {
5241 /* add closing pt for bezier */
5242 if(buf)
5243 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5244 cpfx++;
5245 point++;
5247 if(buf) {
5248 ppc->wType = type;
5249 ppc->cpfx = cpfx;
5251 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5253 if(buf)
5254 pph->cb = needed - pph_start;
5256 break;
5258 case GGO_BEZIER:
5260 /* Convert the quadratic Beziers to cubic Beziers.
5261 The parametric eqn for a cubic Bezier is, from PLRM:
5262 r(t) = at^3 + bt^2 + ct + r0
5263 with the control points:
5264 r1 = r0 + c/3
5265 r2 = r1 + (c + b)/3
5266 r3 = r0 + c + b + a
5268 A quadratic Bezier has the form:
5269 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5271 So equating powers of t leads to:
5272 r1 = 2/3 p1 + 1/3 p0
5273 r2 = 2/3 p1 + 1/3 p2
5274 and of course r0 = p0, r3 = p2
5277 int contour, point = 0, first_pt;
5278 FT_Outline *outline = &ft_face->glyph->outline;
5279 TTPOLYGONHEADER *pph;
5280 TTPOLYCURVE *ppc;
5281 DWORD pph_start, cpfx, type;
5282 FT_Vector cubic_control[4];
5283 if(buflen == 0) buf = NULL;
5285 if (needsTransform && buf) {
5286 pFT_Outline_Transform(outline, &transMat);
5289 for(contour = 0; contour < outline->n_contours; contour++) {
5290 pph_start = needed;
5291 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5292 first_pt = point;
5293 if(buf) {
5294 pph->dwType = TT_POLYGON_TYPE;
5295 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5297 needed += sizeof(*pph);
5298 point++;
5299 while(point <= outline->contours[contour]) {
5300 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5301 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5302 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5303 cpfx = 0;
5304 do {
5305 if(type == TT_PRIM_LINE) {
5306 if(buf)
5307 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5308 cpfx++;
5309 point++;
5310 } else {
5311 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5312 so cpfx = 3n */
5314 /* FIXME: Possible optimization in endpoint calculation
5315 if there are two consecutive curves */
5316 cubic_control[0] = outline->points[point-1];
5317 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5318 cubic_control[0].x += outline->points[point].x + 1;
5319 cubic_control[0].y += outline->points[point].y + 1;
5320 cubic_control[0].x >>= 1;
5321 cubic_control[0].y >>= 1;
5323 if(point+1 > outline->contours[contour])
5324 cubic_control[3] = outline->points[first_pt];
5325 else {
5326 cubic_control[3] = outline->points[point+1];
5327 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5328 cubic_control[3].x += outline->points[point].x + 1;
5329 cubic_control[3].y += outline->points[point].y + 1;
5330 cubic_control[3].x >>= 1;
5331 cubic_control[3].y >>= 1;
5334 /* r1 = 1/3 p0 + 2/3 p1
5335 r2 = 1/3 p2 + 2/3 p1 */
5336 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5337 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5338 cubic_control[2] = cubic_control[1];
5339 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5340 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5341 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5342 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5343 if(buf) {
5344 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5345 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5346 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5348 cpfx += 3;
5349 point++;
5351 } while(point <= outline->contours[contour] &&
5352 (outline->tags[point] & FT_Curve_Tag_On) ==
5353 (outline->tags[point-1] & FT_Curve_Tag_On));
5354 /* At the end of a contour Windows adds the start point,
5355 but only for Beziers and we've already done that.
5357 if(point <= outline->contours[contour] &&
5358 outline->tags[point] & FT_Curve_Tag_On) {
5359 /* This is the closing pt of a bezier, but we've already
5360 added it, so just inc point and carry on */
5361 point++;
5363 if(buf) {
5364 ppc->wType = type;
5365 ppc->cpfx = cpfx;
5367 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5369 if(buf)
5370 pph->cb = needed - pph_start;
5372 break;
5375 default:
5376 FIXME("Unsupported format %d\n", format);
5377 LeaveCriticalSection( &freetype_cs );
5378 return GDI_ERROR;
5380 LeaveCriticalSection( &freetype_cs );
5381 return needed;
5384 static BOOL get_bitmap_text_metrics(GdiFont *font)
5386 FT_Face ft_face = font->ft_face;
5387 #ifdef HAVE_FREETYPE_FTWINFNT_H
5388 FT_WinFNT_HeaderRec winfnt_header;
5389 #endif
5390 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5391 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5392 font->potm->otmSize = size;
5394 #define TM font->potm->otmTextMetrics
5395 #ifdef HAVE_FREETYPE_FTWINFNT_H
5396 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5398 TM.tmHeight = winfnt_header.pixel_height;
5399 TM.tmAscent = winfnt_header.ascent;
5400 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5401 TM.tmInternalLeading = winfnt_header.internal_leading;
5402 TM.tmExternalLeading = winfnt_header.external_leading;
5403 TM.tmAveCharWidth = winfnt_header.avg_width;
5404 TM.tmMaxCharWidth = winfnt_header.max_width;
5405 TM.tmWeight = winfnt_header.weight;
5406 TM.tmOverhang = 0;
5407 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5408 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5409 TM.tmFirstChar = winfnt_header.first_char;
5410 TM.tmLastChar = winfnt_header.last_char;
5411 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5412 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5413 TM.tmItalic = winfnt_header.italic;
5414 TM.tmUnderlined = font->underline;
5415 TM.tmStruckOut = font->strikeout;
5416 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5417 TM.tmCharSet = winfnt_header.charset;
5419 else
5420 #endif
5422 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5423 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5424 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5425 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5426 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5427 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5428 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5429 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5430 TM.tmOverhang = 0;
5431 TM.tmDigitizedAspectX = 96; /* FIXME */
5432 TM.tmDigitizedAspectY = 96; /* FIXME */
5433 TM.tmFirstChar = 1;
5434 TM.tmLastChar = 255;
5435 TM.tmDefaultChar = 32;
5436 TM.tmBreakChar = 32;
5437 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5438 TM.tmUnderlined = font->underline;
5439 TM.tmStruckOut = font->strikeout;
5440 /* NB inverted meaning of TMPF_FIXED_PITCH */
5441 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5442 TM.tmCharSet = font->charset;
5444 #undef TM
5446 return TRUE;
5450 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5452 double scale_x, scale_y;
5454 if (font->aveWidth)
5456 scale_x = (double)font->aveWidth;
5457 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5459 else
5460 scale_x = font->scale_y;
5462 scale_x *= fabs(font->font_desc.matrix.eM11);
5463 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5465 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5466 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5468 SCALE_Y(ptm->tmHeight);
5469 SCALE_Y(ptm->tmAscent);
5470 SCALE_Y(ptm->tmDescent);
5471 SCALE_Y(ptm->tmInternalLeading);
5472 SCALE_Y(ptm->tmExternalLeading);
5473 SCALE_Y(ptm->tmOverhang);
5475 SCALE_X(ptm->tmAveCharWidth);
5476 SCALE_X(ptm->tmMaxCharWidth);
5478 #undef SCALE_X
5479 #undef SCALE_Y
5482 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5484 double scale_x, scale_y;
5486 if (font->aveWidth)
5488 scale_x = (double)font->aveWidth;
5489 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5491 else
5492 scale_x = font->scale_y;
5494 scale_x *= fabs(font->font_desc.matrix.eM11);
5495 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5497 scale_font_metrics(font, &potm->otmTextMetrics);
5499 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5500 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5502 SCALE_Y(potm->otmAscent);
5503 SCALE_Y(potm->otmDescent);
5504 SCALE_Y(potm->otmLineGap);
5505 SCALE_Y(potm->otmsCapEmHeight);
5506 SCALE_Y(potm->otmsXHeight);
5507 SCALE_Y(potm->otmrcFontBox.top);
5508 SCALE_Y(potm->otmrcFontBox.bottom);
5509 SCALE_X(potm->otmrcFontBox.left);
5510 SCALE_X(potm->otmrcFontBox.right);
5511 SCALE_Y(potm->otmMacAscent);
5512 SCALE_Y(potm->otmMacDescent);
5513 SCALE_Y(potm->otmMacLineGap);
5514 SCALE_X(potm->otmptSubscriptSize.x);
5515 SCALE_Y(potm->otmptSubscriptSize.y);
5516 SCALE_X(potm->otmptSubscriptOffset.x);
5517 SCALE_Y(potm->otmptSubscriptOffset.y);
5518 SCALE_X(potm->otmptSuperscriptSize.x);
5519 SCALE_Y(potm->otmptSuperscriptSize.y);
5520 SCALE_X(potm->otmptSuperscriptOffset.x);
5521 SCALE_Y(potm->otmptSuperscriptOffset.y);
5522 SCALE_Y(potm->otmsStrikeoutSize);
5523 SCALE_Y(potm->otmsStrikeoutPosition);
5524 SCALE_Y(potm->otmsUnderscoreSize);
5525 SCALE_Y(potm->otmsUnderscorePosition);
5527 #undef SCALE_X
5528 #undef SCALE_Y
5531 /*************************************************************
5532 * WineEngGetTextMetrics
5535 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5537 GDI_CheckNotLock();
5538 EnterCriticalSection( &freetype_cs );
5539 if(!font->potm) {
5540 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5541 if(!get_bitmap_text_metrics(font))
5543 LeaveCriticalSection( &freetype_cs );
5544 return FALSE;
5547 /* Make sure that the font has sane width/height ratio */
5548 if (font->aveWidth)
5550 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5552 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5553 font->aveWidth = 0;
5558 *ptm = font->potm->otmTextMetrics;
5559 scale_font_metrics(font, ptm);
5560 LeaveCriticalSection( &freetype_cs );
5561 return TRUE;
5564 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5566 int i;
5568 for(i = 0; i < ft_face->num_charmaps; i++)
5570 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5571 return TRUE;
5573 return FALSE;
5576 /*************************************************************
5577 * WineEngGetOutlineTextMetrics
5580 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5581 OUTLINETEXTMETRICW *potm)
5583 FT_Face ft_face = font->ft_face;
5584 UINT needed, lenfam, lensty, ret;
5585 TT_OS2 *pOS2;
5586 TT_HoriHeader *pHori;
5587 TT_Postscript *pPost;
5588 FT_Fixed x_scale, y_scale;
5589 WCHAR *family_nameW, *style_nameW;
5590 static const WCHAR spaceW[] = {' ', '\0'};
5591 char *cp;
5592 INT ascent, descent;
5594 TRACE("font=%p\n", font);
5596 if(!FT_IS_SCALABLE(ft_face))
5597 return 0;
5599 GDI_CheckNotLock();
5600 EnterCriticalSection( &freetype_cs );
5602 if(font->potm) {
5603 if(cbSize >= font->potm->otmSize)
5605 memcpy(potm, font->potm, font->potm->otmSize);
5606 scale_outline_font_metrics(font, potm);
5608 LeaveCriticalSection( &freetype_cs );
5609 return font->potm->otmSize;
5613 needed = sizeof(*potm);
5615 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5616 family_nameW = strdupW(font->name);
5618 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5619 * sizeof(WCHAR);
5620 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5621 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5622 style_nameW, lensty/sizeof(WCHAR));
5624 /* These names should be read from the TT name table */
5626 /* length of otmpFamilyName */
5627 needed += lenfam;
5629 /* length of otmpFaceName */
5630 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5631 needed += lenfam; /* just the family name */
5632 } else {
5633 needed += lenfam + lensty; /* family + " " + style */
5636 /* length of otmpStyleName */
5637 needed += lensty;
5639 /* length of otmpFullName */
5640 needed += lenfam + lensty;
5643 x_scale = ft_face->size->metrics.x_scale;
5644 y_scale = ft_face->size->metrics.y_scale;
5646 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5647 if(!pOS2) {
5648 FIXME("Can't find OS/2 table - not TT font?\n");
5649 ret = 0;
5650 goto end;
5653 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5654 if(!pHori) {
5655 FIXME("Can't find HHEA table - not TT font?\n");
5656 ret = 0;
5657 goto end;
5660 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5662 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",
5663 pOS2->usWinAscent, pOS2->usWinDescent,
5664 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5665 ft_face->ascender, ft_face->descender, ft_face->height,
5666 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5667 ft_face->bbox.yMax, ft_face->bbox.yMin);
5669 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5670 font->potm->otmSize = needed;
5672 #define TM font->potm->otmTextMetrics
5674 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5675 ascent = pHori->Ascender;
5676 descent = -pHori->Descender;
5677 } else {
5678 ascent = pOS2->usWinAscent;
5679 descent = pOS2->usWinDescent;
5682 if(font->yMax) {
5683 TM.tmAscent = font->yMax;
5684 TM.tmDescent = -font->yMin;
5685 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5686 } else {
5687 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5688 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5689 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5690 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5693 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5695 /* MSDN says:
5696 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5698 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5699 ((ascent + descent) -
5700 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5702 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5703 if (TM.tmAveCharWidth == 0) {
5704 TM.tmAveCharWidth = 1;
5706 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5707 TM.tmWeight = FW_REGULAR;
5708 if (font->fake_bold)
5709 TM.tmWeight = FW_BOLD;
5710 else
5712 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5714 if (pOS2->usWeightClass > FW_MEDIUM)
5715 TM.tmWeight = pOS2->usWeightClass;
5717 else if (pOS2->usWeightClass <= FW_MEDIUM)
5718 TM.tmWeight = pOS2->usWeightClass;
5720 TM.tmOverhang = 0;
5721 TM.tmDigitizedAspectX = 300;
5722 TM.tmDigitizedAspectY = 300;
5723 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5724 * symbol range to 0 - f0ff
5727 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5729 TM.tmFirstChar = 0;
5730 switch(GetACP())
5732 case 1257: /* Baltic */
5733 TM.tmLastChar = 0xf8fd;
5734 break;
5735 default:
5736 TM.tmLastChar = 0xf0ff;
5738 TM.tmBreakChar = 0x20;
5739 TM.tmDefaultChar = 0x1f;
5741 else
5743 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5744 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5746 if(pOS2->usFirstCharIndex <= 1)
5747 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5748 else if (pOS2->usFirstCharIndex > 0xff)
5749 TM.tmBreakChar = 0x20;
5750 else
5751 TM.tmBreakChar = pOS2->usFirstCharIndex;
5752 TM.tmDefaultChar = TM.tmBreakChar - 1;
5754 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5755 TM.tmUnderlined = font->underline;
5756 TM.tmStruckOut = font->strikeout;
5758 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5759 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5760 (pOS2->version == 0xFFFFU ||
5761 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5762 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5763 else
5764 TM.tmPitchAndFamily = 0;
5766 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5768 case PAN_FAMILY_SCRIPT:
5769 TM.tmPitchAndFamily |= FF_SCRIPT;
5770 break;
5772 case PAN_FAMILY_DECORATIVE:
5773 TM.tmPitchAndFamily |= FF_DECORATIVE;
5774 break;
5776 case PAN_ANY:
5777 case PAN_NO_FIT:
5778 case PAN_FAMILY_TEXT_DISPLAY:
5779 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5780 /* which is clearly not what the panose spec says. */
5781 default:
5782 if(TM.tmPitchAndFamily == 0 || /* fixed */
5783 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5784 TM.tmPitchAndFamily = FF_MODERN;
5785 else
5787 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5789 case PAN_ANY:
5790 case PAN_NO_FIT:
5791 default:
5792 TM.tmPitchAndFamily |= FF_DONTCARE;
5793 break;
5795 case PAN_SERIF_COVE:
5796 case PAN_SERIF_OBTUSE_COVE:
5797 case PAN_SERIF_SQUARE_COVE:
5798 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5799 case PAN_SERIF_SQUARE:
5800 case PAN_SERIF_THIN:
5801 case PAN_SERIF_BONE:
5802 case PAN_SERIF_EXAGGERATED:
5803 case PAN_SERIF_TRIANGLE:
5804 TM.tmPitchAndFamily |= FF_ROMAN;
5805 break;
5807 case PAN_SERIF_NORMAL_SANS:
5808 case PAN_SERIF_OBTUSE_SANS:
5809 case PAN_SERIF_PERP_SANS:
5810 case PAN_SERIF_FLARED:
5811 case PAN_SERIF_ROUNDED:
5812 TM.tmPitchAndFamily |= FF_SWISS;
5813 break;
5816 break;
5819 if(FT_IS_SCALABLE(ft_face))
5820 TM.tmPitchAndFamily |= TMPF_VECTOR;
5822 if(FT_IS_SFNT(ft_face))
5824 if (font->ntmFlags & NTM_PS_OPENTYPE)
5825 TM.tmPitchAndFamily |= TMPF_DEVICE;
5826 else
5827 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5830 TM.tmCharSet = font->charset;
5832 font->potm->otmFiller = 0;
5833 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5834 font->potm->otmfsSelection = pOS2->fsSelection;
5835 font->potm->otmfsType = pOS2->fsType;
5836 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5837 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5838 font->potm->otmItalicAngle = 0; /* POST table */
5839 font->potm->otmEMSquare = ft_face->units_per_EM;
5840 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5841 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5842 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5843 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5844 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5845 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5846 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5847 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5848 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5849 font->potm->otmMacAscent = TM.tmAscent;
5850 font->potm->otmMacDescent = -TM.tmDescent;
5851 font->potm->otmMacLineGap = font->potm->otmLineGap;
5852 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5853 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5854 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5855 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5856 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5857 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5858 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5859 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5860 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5861 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5862 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5863 if(!pPost) {
5864 font->potm->otmsUnderscoreSize = 0;
5865 font->potm->otmsUnderscorePosition = 0;
5866 } else {
5867 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5868 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5870 #undef TM
5872 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5873 cp = (char*)font->potm + sizeof(*font->potm);
5874 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5875 strcpyW((WCHAR*)cp, family_nameW);
5876 cp += lenfam;
5877 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5878 strcpyW((WCHAR*)cp, style_nameW);
5879 cp += lensty;
5880 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5881 strcpyW((WCHAR*)cp, family_nameW);
5882 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5883 strcatW((WCHAR*)cp, spaceW);
5884 strcatW((WCHAR*)cp, style_nameW);
5885 cp += lenfam + lensty;
5886 } else
5887 cp += lenfam;
5888 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5889 strcpyW((WCHAR*)cp, family_nameW);
5890 strcatW((WCHAR*)cp, spaceW);
5891 strcatW((WCHAR*)cp, style_nameW);
5892 ret = needed;
5894 if(potm && needed <= cbSize)
5896 memcpy(potm, font->potm, font->potm->otmSize);
5897 scale_outline_font_metrics(font, potm);
5900 end:
5901 HeapFree(GetProcessHeap(), 0, style_nameW);
5902 HeapFree(GetProcessHeap(), 0, family_nameW);
5904 LeaveCriticalSection( &freetype_cs );
5905 return ret;
5908 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5910 HFONTLIST *hfontlist;
5911 child->font = alloc_font();
5912 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5913 if(!child->font->ft_face)
5915 free_font(child->font);
5916 child->font = NULL;
5917 return FALSE;
5920 child->font->font_desc = font->font_desc;
5921 child->font->ntmFlags = child->face->ntmFlags;
5922 child->font->orientation = font->orientation;
5923 child->font->scale_y = font->scale_y;
5924 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5925 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5926 child->font->name = strdupW(child->face->family->FamilyName);
5927 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5928 child->font->base_font = font;
5929 list_add_head(&child_font_list, &child->font->entry);
5930 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5931 return TRUE;
5934 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5936 FT_UInt g;
5937 CHILD_FONT *child_font;
5939 if(font->base_font)
5940 font = font->base_font;
5942 *linked_font = font;
5944 if((*glyph = get_glyph_index(font, c)))
5945 return TRUE;
5947 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5949 if(!child_font->font)
5950 if(!load_child_font(font, child_font))
5951 continue;
5953 if(!child_font->font->ft_face)
5954 continue;
5955 g = get_glyph_index(child_font->font, c);
5956 if(g)
5958 *glyph = g;
5959 *linked_font = child_font->font;
5960 return TRUE;
5963 return FALSE;
5966 /*************************************************************
5967 * WineEngGetCharWidth
5970 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5971 LPINT buffer)
5973 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5974 UINT c;
5975 GLYPHMETRICS gm;
5976 FT_UInt glyph_index;
5977 GdiFont *linked_font;
5979 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5981 GDI_CheckNotLock();
5982 EnterCriticalSection( &freetype_cs );
5983 for(c = firstChar; c <= lastChar; c++) {
5984 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5985 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5986 &gm, 0, NULL, &identity);
5987 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5989 LeaveCriticalSection( &freetype_cs );
5990 return TRUE;
5993 /*************************************************************
5994 * WineEngGetCharABCWidths
5997 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5998 LPABC buffer)
6000 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6001 UINT c;
6002 GLYPHMETRICS gm;
6003 FT_UInt glyph_index;
6004 GdiFont *linked_font;
6006 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6008 if(!FT_IS_SCALABLE(font->ft_face))
6009 return FALSE;
6011 GDI_CheckNotLock();
6012 EnterCriticalSection( &freetype_cs );
6014 for(c = firstChar; c <= lastChar; c++) {
6015 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6016 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6017 &gm, 0, NULL, &identity);
6018 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6019 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6020 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6021 FONT_GM(linked_font,glyph_index)->bbx;
6023 LeaveCriticalSection( &freetype_cs );
6024 return TRUE;
6027 /*************************************************************
6028 * WineEngGetCharABCWidthsFloat
6031 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6033 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6034 UINT c;
6035 GLYPHMETRICS gm;
6036 FT_UInt glyph_index;
6037 GdiFont *linked_font;
6039 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6041 GDI_CheckNotLock();
6042 EnterCriticalSection( &freetype_cs );
6044 for (c = first; c <= last; c++)
6046 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6047 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6048 &gm, 0, NULL, &identity);
6049 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6050 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6051 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6052 FONT_GM(linked_font, glyph_index)->lsb -
6053 FONT_GM(linked_font, glyph_index)->bbx;
6055 LeaveCriticalSection( &freetype_cs );
6056 return TRUE;
6059 /*************************************************************
6060 * WineEngGetCharABCWidthsI
6063 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6064 LPABC buffer)
6066 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6067 UINT c;
6068 GLYPHMETRICS gm;
6069 FT_UInt glyph_index;
6070 GdiFont *linked_font;
6072 if(!FT_HAS_HORIZONTAL(font->ft_face))
6073 return FALSE;
6075 GDI_CheckNotLock();
6076 EnterCriticalSection( &freetype_cs );
6078 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6079 if (!pgi)
6080 for(c = firstChar; c < firstChar+count; c++) {
6081 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6082 &gm, 0, NULL, &identity);
6083 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6084 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6085 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6086 - FONT_GM(linked_font,c)->bbx;
6088 else
6089 for(c = 0; c < count; c++) {
6090 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6091 &gm, 0, NULL, &identity);
6092 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6093 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6094 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6095 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6098 LeaveCriticalSection( &freetype_cs );
6099 return TRUE;
6102 /*************************************************************
6103 * WineEngGetTextExtentExPoint
6106 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6107 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6109 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6110 INT idx;
6111 INT nfit = 0, ext;
6112 GLYPHMETRICS gm;
6113 TEXTMETRICW tm;
6114 FT_UInt glyph_index;
6115 GdiFont *linked_font;
6117 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6118 max_ext, size);
6120 GDI_CheckNotLock();
6121 EnterCriticalSection( &freetype_cs );
6123 size->cx = 0;
6124 WineEngGetTextMetrics(font, &tm);
6125 size->cy = tm.tmHeight;
6127 for(idx = 0; idx < count; idx++) {
6128 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6129 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6130 &gm, 0, NULL, &identity);
6131 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6132 ext = size->cx;
6133 if (! pnfit || ext <= max_ext) {
6134 ++nfit;
6135 if (dxs)
6136 dxs[idx] = ext;
6140 if (pnfit)
6141 *pnfit = nfit;
6143 LeaveCriticalSection( &freetype_cs );
6144 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6145 return TRUE;
6148 /*************************************************************
6149 * WineEngGetTextExtentExPointI
6152 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6153 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6155 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6156 INT idx;
6157 INT nfit = 0, ext;
6158 GLYPHMETRICS gm;
6159 TEXTMETRICW tm;
6161 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6163 GDI_CheckNotLock();
6164 EnterCriticalSection( &freetype_cs );
6166 size->cx = 0;
6167 WineEngGetTextMetrics(font, &tm);
6168 size->cy = tm.tmHeight;
6170 for(idx = 0; idx < count; idx++) {
6171 WineEngGetGlyphOutline(font, indices[idx],
6172 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6173 &identity);
6174 size->cx += FONT_GM(font,indices[idx])->adv;
6175 ext = size->cx;
6176 if (! pnfit || ext <= max_ext) {
6177 ++nfit;
6178 if (dxs)
6179 dxs[idx] = ext;
6183 if (pnfit)
6184 *pnfit = nfit;
6186 LeaveCriticalSection( &freetype_cs );
6187 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6188 return TRUE;
6191 /*************************************************************
6192 * WineEngGetFontData
6195 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6196 DWORD cbData)
6198 FT_Face ft_face = font->ft_face;
6199 FT_ULong len;
6200 FT_Error err;
6202 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6203 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6204 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6206 if(!FT_IS_SFNT(ft_face))
6207 return GDI_ERROR;
6209 if(!buf)
6210 len = 0;
6211 else
6212 len = cbData;
6214 if(table) { /* MS tags differ in endianness from FT ones */
6215 table = table >> 24 | table << 24 |
6216 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6219 /* make sure value of len is the value freetype says it needs */
6220 if(buf && len)
6222 FT_ULong needed = 0;
6223 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6224 if( !err && needed < len) len = needed;
6226 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6228 if(err) {
6229 TRACE("Can't find table %c%c%c%c\n",
6230 /* bytes were reversed */
6231 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6232 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6233 return GDI_ERROR;
6235 return len;
6238 /*************************************************************
6239 * WineEngGetTextFace
6242 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6244 INT n = strlenW(font->name) + 1;
6245 if(str) {
6246 lstrcpynW(str, font->name, count);
6247 return min(count, n);
6248 } else
6249 return n;
6252 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6254 if (fs) *fs = font->fs;
6255 return font->charset;
6258 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6260 GdiFont *font = dc->gdiFont, *linked_font;
6261 struct list *first_hfont;
6262 BOOL ret;
6264 GDI_CheckNotLock();
6265 EnterCriticalSection( &freetype_cs );
6266 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6267 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6268 if(font == linked_font)
6269 *new_hfont = dc->hFont;
6270 else
6272 first_hfont = list_head(&linked_font->hfontlist);
6273 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6275 LeaveCriticalSection( &freetype_cs );
6276 return ret;
6279 /* Retrieve a list of supported Unicode ranges for a given font.
6280 * Can be called with NULL gs to calculate the buffer size. Returns
6281 * the number of ranges found.
6283 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6285 DWORD num_ranges = 0;
6287 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6289 FT_UInt glyph_code;
6290 FT_ULong char_code, char_code_prev;
6292 glyph_code = 0;
6293 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6295 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6296 face->num_glyphs, glyph_code, char_code);
6298 if (!glyph_code) return 0;
6300 if (gs)
6302 gs->ranges[0].wcLow = (USHORT)char_code;
6303 gs->ranges[0].cGlyphs = 0;
6304 gs->cGlyphsSupported = 0;
6307 num_ranges = 1;
6308 while (glyph_code)
6310 if (char_code < char_code_prev)
6312 ERR("expected increasing char code from FT_Get_Next_Char\n");
6313 return 0;
6315 if (char_code - char_code_prev > 1)
6317 num_ranges++;
6318 if (gs)
6320 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6321 gs->ranges[num_ranges - 1].cGlyphs = 1;
6322 gs->cGlyphsSupported++;
6325 else if (gs)
6327 gs->ranges[num_ranges - 1].cGlyphs++;
6328 gs->cGlyphsSupported++;
6330 char_code_prev = char_code;
6331 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6334 else
6335 FIXME("encoding %u not supported\n", face->charmap->encoding);
6337 return num_ranges;
6340 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6342 DWORD size = 0;
6343 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6345 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6346 if (glyphset)
6348 glyphset->cbThis = size;
6349 glyphset->cRanges = num_ranges;
6350 glyphset->flAccel = 0;
6352 return size;
6355 /*************************************************************
6356 * FontIsLinked
6358 BOOL WineEngFontIsLinked(GdiFont *font)
6360 BOOL ret;
6361 GDI_CheckNotLock();
6362 EnterCriticalSection( &freetype_cs );
6363 ret = !list_empty(&font->child_fonts);
6364 LeaveCriticalSection( &freetype_cs );
6365 return ret;
6368 static BOOL is_hinting_enabled(void)
6370 /* Use the >= 2.2.0 function if available */
6371 if(pFT_Get_TrueType_Engine_Type)
6373 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6374 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6376 #ifdef FT_DRIVER_HAS_HINTER
6377 else
6379 FT_Module mod;
6381 /* otherwise if we've been compiled with < 2.2.0 headers
6382 use the internal macro */
6383 mod = pFT_Get_Module(library, "truetype");
6384 if(mod && FT_DRIVER_HAS_HINTER(mod))
6385 return TRUE;
6387 #endif
6389 return FALSE;
6392 static BOOL is_subpixel_rendering_enabled( void )
6394 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6395 return pFT_Library_SetLcdFilter &&
6396 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6397 #else
6398 return FALSE;
6399 #endif
6402 /*************************************************************************
6403 * GetRasterizerCaps (GDI32.@)
6405 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6407 static int hinting = -1;
6408 static int subpixel = -1;
6410 if(hinting == -1)
6412 hinting = is_hinting_enabled();
6413 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6416 if ( subpixel == -1 )
6418 subpixel = is_subpixel_rendering_enabled();
6419 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6422 lprs->nSize = sizeof(RASTERIZER_STATUS);
6423 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6424 if ( subpixel )
6425 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6426 lprs->nLanguageID = 0;
6427 return TRUE;
6430 /*************************************************************
6431 * WineEngRealizationInfo
6433 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6435 FIXME("(%p, %p): stub!\n", font, info);
6437 info->flags = 1;
6438 if(FT_IS_SCALABLE(font->ft_face))
6439 info->flags |= 2;
6441 info->cache_num = font->cache_num;
6442 info->unknown2 = -1;
6443 return TRUE;
6446 /*************************************************************************
6447 * Kerning support for TrueType fonts
6449 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6451 struct TT_kern_table
6453 USHORT version;
6454 USHORT nTables;
6457 struct TT_kern_subtable
6459 USHORT version;
6460 USHORT length;
6461 union
6463 USHORT word;
6464 struct
6466 USHORT horizontal : 1;
6467 USHORT minimum : 1;
6468 USHORT cross_stream: 1;
6469 USHORT override : 1;
6470 USHORT reserved1 : 4;
6471 USHORT format : 8;
6472 } bits;
6473 } coverage;
6476 struct TT_format0_kern_subtable
6478 USHORT nPairs;
6479 USHORT searchRange;
6480 USHORT entrySelector;
6481 USHORT rangeShift;
6484 struct TT_kern_pair
6486 USHORT left;
6487 USHORT right;
6488 short value;
6491 static DWORD parse_format0_kern_subtable(GdiFont *font,
6492 const struct TT_format0_kern_subtable *tt_f0_ks,
6493 const USHORT *glyph_to_char,
6494 KERNINGPAIR *kern_pair, DWORD cPairs)
6496 USHORT i, nPairs;
6497 const struct TT_kern_pair *tt_kern_pair;
6499 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6501 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6503 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6504 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6505 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6507 if (!kern_pair || !cPairs)
6508 return nPairs;
6510 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6512 nPairs = min(nPairs, cPairs);
6514 for (i = 0; i < nPairs; i++)
6516 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6517 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6518 /* this algorithm appears to better match what Windows does */
6519 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6520 if (kern_pair->iKernAmount < 0)
6522 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6523 kern_pair->iKernAmount -= font->ppem;
6525 else if (kern_pair->iKernAmount > 0)
6527 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6528 kern_pair->iKernAmount += font->ppem;
6530 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6532 TRACE("left %u right %u value %d\n",
6533 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6535 kern_pair++;
6537 TRACE("copied %u entries\n", nPairs);
6538 return nPairs;
6541 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6543 DWORD length;
6544 void *buf;
6545 const struct TT_kern_table *tt_kern_table;
6546 const struct TT_kern_subtable *tt_kern_subtable;
6547 USHORT i, nTables;
6548 USHORT *glyph_to_char;
6550 GDI_CheckNotLock();
6551 EnterCriticalSection( &freetype_cs );
6552 if (font->total_kern_pairs != (DWORD)-1)
6554 if (cPairs && kern_pair)
6556 cPairs = min(cPairs, font->total_kern_pairs);
6557 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6558 LeaveCriticalSection( &freetype_cs );
6559 return cPairs;
6561 LeaveCriticalSection( &freetype_cs );
6562 return font->total_kern_pairs;
6565 font->total_kern_pairs = 0;
6567 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6569 if (length == GDI_ERROR)
6571 TRACE("no kerning data in the font\n");
6572 LeaveCriticalSection( &freetype_cs );
6573 return 0;
6576 buf = HeapAlloc(GetProcessHeap(), 0, length);
6577 if (!buf)
6579 WARN("Out of memory\n");
6580 LeaveCriticalSection( &freetype_cs );
6581 return 0;
6584 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6586 /* build a glyph index to char code map */
6587 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6588 if (!glyph_to_char)
6590 WARN("Out of memory allocating a glyph index to char code map\n");
6591 HeapFree(GetProcessHeap(), 0, buf);
6592 LeaveCriticalSection( &freetype_cs );
6593 return 0;
6596 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6598 FT_UInt glyph_code;
6599 FT_ULong char_code;
6601 glyph_code = 0;
6602 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6604 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6605 font->ft_face->num_glyphs, glyph_code, char_code);
6607 while (glyph_code)
6609 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6611 /* FIXME: This doesn't match what Windows does: it does some fancy
6612 * things with duplicate glyph index to char code mappings, while
6613 * we just avoid overriding existing entries.
6615 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6616 glyph_to_char[glyph_code] = (USHORT)char_code;
6618 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6621 else
6623 ULONG n;
6625 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6626 for (n = 0; n <= 65535; n++)
6627 glyph_to_char[n] = (USHORT)n;
6630 tt_kern_table = buf;
6631 nTables = GET_BE_WORD(tt_kern_table->nTables);
6632 TRACE("version %u, nTables %u\n",
6633 GET_BE_WORD(tt_kern_table->version), nTables);
6635 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6637 for (i = 0; i < nTables; i++)
6639 struct TT_kern_subtable tt_kern_subtable_copy;
6641 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6642 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6643 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6645 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6646 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6647 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6649 /* According to the TrueType specification this is the only format
6650 * that will be properly interpreted by Windows and OS/2
6652 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6654 DWORD new_chunk, old_total = font->total_kern_pairs;
6656 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6657 glyph_to_char, NULL, 0);
6658 font->total_kern_pairs += new_chunk;
6660 if (!font->kern_pairs)
6661 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6662 font->total_kern_pairs * sizeof(*font->kern_pairs));
6663 else
6664 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6665 font->total_kern_pairs * sizeof(*font->kern_pairs));
6667 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6668 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6670 else
6671 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6673 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6676 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6677 HeapFree(GetProcessHeap(), 0, buf);
6679 if (cPairs && kern_pair)
6681 cPairs = min(cPairs, font->total_kern_pairs);
6682 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6683 LeaveCriticalSection( &freetype_cs );
6684 return cPairs;
6686 LeaveCriticalSection( &freetype_cs );
6687 return font->total_kern_pairs;
6690 #else /* HAVE_FREETYPE */
6692 /*************************************************************************/
6694 BOOL WineEngInit(void)
6696 return FALSE;
6698 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6700 return NULL;
6702 BOOL WineEngDestroyFontInstance(HFONT hfont)
6704 return FALSE;
6707 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6709 return 1;
6712 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6713 LPWORD pgi, DWORD flags)
6715 return GDI_ERROR;
6718 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6719 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6720 const MAT2* lpmat)
6722 ERR("called but we don't have FreeType\n");
6723 return GDI_ERROR;
6726 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6728 ERR("called but we don't have FreeType\n");
6729 return FALSE;
6732 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6733 OUTLINETEXTMETRICW *potm)
6735 ERR("called but we don't have FreeType\n");
6736 return 0;
6739 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6740 LPINT buffer)
6742 ERR("called but we don't have FreeType\n");
6743 return FALSE;
6746 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6747 LPABC buffer)
6749 ERR("called but we don't have FreeType\n");
6750 return FALSE;
6753 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6755 ERR("called but we don't have FreeType\n");
6756 return FALSE;
6759 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6760 LPABC buffer)
6762 ERR("called but we don't have FreeType\n");
6763 return FALSE;
6766 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6767 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6769 ERR("called but we don't have FreeType\n");
6770 return FALSE;
6773 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6774 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6776 ERR("called but we don't have FreeType\n");
6777 return FALSE;
6780 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6781 DWORD cbData)
6783 ERR("called but we don't have FreeType\n");
6784 return GDI_ERROR;
6787 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6789 ERR("called but we don't have FreeType\n");
6790 return 0;
6793 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6795 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6796 return 1;
6799 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6801 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6802 return TRUE;
6805 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6807 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6808 return NULL;
6811 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6813 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6814 return DEFAULT_CHARSET;
6817 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6819 return FALSE;
6822 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6824 FIXME("(%p, %p): stub\n", font, glyphset);
6825 return 0;
6828 BOOL WineEngFontIsLinked(GdiFont *font)
6830 return FALSE;
6833 /*************************************************************************
6834 * GetRasterizerCaps (GDI32.@)
6836 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6838 lprs->nSize = sizeof(RASTERIZER_STATUS);
6839 lprs->wFlags = 0;
6840 lprs->nLanguageID = 0;
6841 return TRUE;
6844 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6846 ERR("called but we don't have FreeType\n");
6847 return 0;
6850 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6852 ERR("called but we don't have FreeType\n");
6853 return FALSE;
6856 #endif /* HAVE_FREETYPE */