gdi32: Move the font list initialisation to a separate function.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob62c0504cb844dbce978e2036ea37772c1717a99f
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 static void init_font_list(void)
2750 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2751 static const WCHAR pathW[] = {'P','a','t','h',0};
2752 HKEY hkey;
2753 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2754 WCHAR windowsdir[MAX_PATH];
2755 char *unixname;
2756 const char *data_dir;
2758 delete_external_font_keys();
2760 /* load the system bitmap fonts */
2761 load_system_fonts();
2763 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2764 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2765 strcatW(windowsdir, fontsW);
2766 if((unixname = wine_get_unix_file_name(windowsdir)))
2768 ReadFontDir(unixname, FALSE);
2769 HeapFree(GetProcessHeap(), 0, unixname);
2772 /* load the system truetype fonts */
2773 data_dir = wine_get_data_dir();
2774 if (!data_dir) data_dir = wine_get_build_dir();
2775 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
2777 strcpy(unixname, data_dir);
2778 strcat(unixname, "/fonts/");
2779 ReadFontDir(unixname, TRUE);
2780 HeapFree(GetProcessHeap(), 0, unixname);
2783 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2784 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2785 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2786 will skip these. */
2787 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2788 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2789 &hkey) == ERROR_SUCCESS)
2791 LPWSTR data, valueW;
2792 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2793 &valuelen, &datalen, NULL, NULL);
2795 valuelen++; /* returned value doesn't include room for '\0' */
2796 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2797 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2798 if (valueW && data)
2800 dlen = datalen * sizeof(WCHAR);
2801 vlen = valuelen;
2802 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2803 &dlen) == ERROR_SUCCESS)
2805 if(data[0] && (data[1] == ':'))
2807 if((unixname = wine_get_unix_file_name(data)))
2809 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2810 HeapFree(GetProcessHeap(), 0, unixname);
2813 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2815 WCHAR pathW[MAX_PATH];
2816 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2817 BOOL added = FALSE;
2819 sprintfW(pathW, fmtW, windowsdir, data);
2820 if((unixname = wine_get_unix_file_name(pathW)))
2822 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2823 HeapFree(GetProcessHeap(), 0, unixname);
2825 if (!added)
2826 load_font_from_data_dir(data);
2828 /* reset dlen and vlen */
2829 dlen = datalen;
2830 vlen = valuelen;
2833 HeapFree(GetProcessHeap(), 0, data);
2834 HeapFree(GetProcessHeap(), 0, valueW);
2835 RegCloseKey(hkey);
2838 load_fontconfig_fonts();
2840 /* then look in any directories that we've specified in the config file */
2841 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2842 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2844 DWORD len;
2845 LPWSTR valueW;
2846 LPSTR valueA, ptr;
2848 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2850 len += sizeof(WCHAR);
2851 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2852 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2854 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2855 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2856 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2857 TRACE( "got font path %s\n", debugstr_a(valueA) );
2858 ptr = valueA;
2859 while (ptr)
2861 LPSTR next = strchr( ptr, ':' );
2862 if (next) *next++ = 0;
2863 ReadFontDir( ptr, TRUE );
2864 ptr = next;
2866 HeapFree( GetProcessHeap(), 0, valueA );
2868 HeapFree( GetProcessHeap(), 0, valueW );
2870 RegCloseKey(hkey);
2874 /*************************************************************
2875 * WineEngInit
2877 * Initialize FreeType library and create a list of available faces
2879 BOOL WineEngInit(void)
2881 HANDLE font_mutex;
2883 /* update locale dependent font info in registry */
2884 update_font_info();
2886 if(!init_freetype()) return FALSE;
2888 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
2890 ERR("Failed to create font mutex\n");
2891 return FALSE;
2893 WaitForSingleObject(font_mutex, INFINITE);
2895 init_font_list();
2897 DumpFontList();
2898 LoadSubstList();
2899 DumpSubstList();
2900 LoadReplaceList();
2901 update_reg_entries();
2903 update_system_links();
2904 init_system_links();
2906 ReleaseMutex(font_mutex);
2907 return TRUE;
2911 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2913 TT_OS2 *pOS2;
2914 TT_HoriHeader *pHori;
2916 LONG ppem;
2918 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2919 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2921 if(height == 0) height = 16;
2923 /* Calc. height of EM square:
2925 * For +ve lfHeight we have
2926 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2927 * Re-arranging gives:
2928 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2930 * For -ve lfHeight we have
2931 * |lfHeight| = ppem
2932 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2933 * with il = winAscent + winDescent - units_per_em]
2937 if(height > 0) {
2938 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2939 ppem = MulDiv(ft_face->units_per_EM, height,
2940 pHori->Ascender - pHori->Descender);
2941 else
2942 ppem = MulDiv(ft_face->units_per_EM, height,
2943 pOS2->usWinAscent + pOS2->usWinDescent);
2945 else
2946 ppem = -height;
2948 return ppem;
2951 static struct font_mapping *map_font_file( const char *name )
2953 struct font_mapping *mapping;
2954 struct stat st;
2955 int fd;
2957 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2958 if (fstat( fd, &st ) == -1) goto error;
2960 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2962 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2964 mapping->refcount++;
2965 close( fd );
2966 return mapping;
2969 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2970 goto error;
2972 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2973 close( fd );
2975 if (mapping->data == MAP_FAILED)
2977 HeapFree( GetProcessHeap(), 0, mapping );
2978 return NULL;
2980 mapping->refcount = 1;
2981 mapping->dev = st.st_dev;
2982 mapping->ino = st.st_ino;
2983 mapping->size = st.st_size;
2984 list_add_tail( &mappings_list, &mapping->entry );
2985 return mapping;
2987 error:
2988 close( fd );
2989 return NULL;
2992 static void unmap_font_file( struct font_mapping *mapping )
2994 if (!--mapping->refcount)
2996 list_remove( &mapping->entry );
2997 munmap( mapping->data, mapping->size );
2998 HeapFree( GetProcessHeap(), 0, mapping );
3002 static LONG load_VDMX(GdiFont*, LONG);
3004 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3006 FT_Error err;
3007 FT_Face ft_face;
3008 void *data_ptr;
3009 DWORD data_size;
3011 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3013 if (face->file)
3015 if (!(font->mapping = map_font_file( face->file )))
3017 WARN("failed to map %s\n", debugstr_a(face->file));
3018 return 0;
3020 data_ptr = font->mapping->data;
3021 data_size = font->mapping->size;
3023 else
3025 data_ptr = face->font_data_ptr;
3026 data_size = face->font_data_size;
3029 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3030 if(err) {
3031 ERR("FT_New_Face rets %d\n", err);
3032 return 0;
3035 /* set it here, as load_VDMX needs it */
3036 font->ft_face = ft_face;
3038 if(FT_IS_SCALABLE(ft_face)) {
3039 /* load the VDMX table if we have one */
3040 font->ppem = load_VDMX(font, height);
3041 if(font->ppem == 0)
3042 font->ppem = calc_ppem_for_height(ft_face, height);
3043 TRACE("height %d => ppem %d\n", height, font->ppem);
3045 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3046 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3047 } else {
3048 font->ppem = height;
3049 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3050 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3052 return ft_face;
3056 static int get_nearest_charset(Face *face, int *cp)
3058 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3059 a single face with the requested charset. The idea is to check if
3060 the selected font supports the current ANSI codepage, if it does
3061 return the corresponding charset, else return the first charset */
3063 CHARSETINFO csi;
3064 int acp = GetACP(), i;
3065 DWORD fs0;
3067 *cp = acp;
3068 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3069 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3070 return csi.ciCharset;
3072 for(i = 0; i < 32; i++) {
3073 fs0 = 1L << i;
3074 if(face->fs.fsCsb[0] & fs0) {
3075 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3076 *cp = csi.ciACP;
3077 return csi.ciCharset;
3079 else
3080 FIXME("TCI failing on %x\n", fs0);
3084 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3085 face->fs.fsCsb[0], face->file);
3086 *cp = acp;
3087 return DEFAULT_CHARSET;
3090 static GdiFont *alloc_font(void)
3092 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3093 ret->gmsize = 1;
3094 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3095 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3096 ret->potm = NULL;
3097 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3098 ret->total_kern_pairs = (DWORD)-1;
3099 ret->kern_pairs = NULL;
3100 list_init(&ret->hfontlist);
3101 list_init(&ret->child_fonts);
3102 return ret;
3105 static void free_font(GdiFont *font)
3107 struct list *cursor, *cursor2;
3108 DWORD i;
3110 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3112 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3113 list_remove(cursor);
3114 if(child->font)
3115 free_font(child->font);
3116 HeapFree(GetProcessHeap(), 0, child);
3119 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3121 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3122 DeleteObject(hfontlist->hfont);
3123 list_remove(&hfontlist->entry);
3124 HeapFree(GetProcessHeap(), 0, hfontlist);
3127 if (font->ft_face) pFT_Done_Face(font->ft_face);
3128 if (font->mapping) unmap_font_file( font->mapping );
3129 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3130 HeapFree(GetProcessHeap(), 0, font->potm);
3131 HeapFree(GetProcessHeap(), 0, font->name);
3132 for (i = 0; i < font->gmsize; i++)
3133 HeapFree(GetProcessHeap(),0,font->gm[i]);
3134 HeapFree(GetProcessHeap(), 0, font->gm);
3135 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3136 HeapFree(GetProcessHeap(), 0, font);
3140 /*************************************************************
3141 * load_VDMX
3143 * load the vdmx entry for the specified height
3146 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3147 ( ( (FT_ULong)_x4 << 24 ) | \
3148 ( (FT_ULong)_x3 << 16 ) | \
3149 ( (FT_ULong)_x2 << 8 ) | \
3150 (FT_ULong)_x1 )
3152 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3154 typedef struct {
3155 BYTE bCharSet;
3156 BYTE xRatio;
3157 BYTE yStartRatio;
3158 BYTE yEndRatio;
3159 } Ratios;
3161 typedef struct {
3162 WORD recs;
3163 BYTE startsz;
3164 BYTE endsz;
3165 } VDMX_group;
3167 static LONG load_VDMX(GdiFont *font, LONG height)
3169 WORD hdr[3], tmp;
3170 VDMX_group group;
3171 BYTE devXRatio, devYRatio;
3172 USHORT numRecs, numRatios;
3173 DWORD result, offset = -1;
3174 LONG ppem = 0;
3175 int i;
3177 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3179 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3180 return ppem;
3182 /* FIXME: need the real device aspect ratio */
3183 devXRatio = 1;
3184 devYRatio = 1;
3186 numRecs = GET_BE_WORD(hdr[1]);
3187 numRatios = GET_BE_WORD(hdr[2]);
3189 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3190 for(i = 0; i < numRatios; i++) {
3191 Ratios ratio;
3193 offset = (3 * 2) + (i * sizeof(Ratios));
3194 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3195 offset = -1;
3197 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3199 if((ratio.xRatio == 0 &&
3200 ratio.yStartRatio == 0 &&
3201 ratio.yEndRatio == 0) ||
3202 (devXRatio == ratio.xRatio &&
3203 devYRatio >= ratio.yStartRatio &&
3204 devYRatio <= ratio.yEndRatio))
3206 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3207 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3208 offset = GET_BE_WORD(tmp);
3209 break;
3213 if(offset == -1) {
3214 FIXME("No suitable ratio found\n");
3215 return ppem;
3218 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3219 USHORT recs;
3220 BYTE startsz, endsz;
3221 WORD *vTable;
3223 recs = GET_BE_WORD(group.recs);
3224 startsz = group.startsz;
3225 endsz = group.endsz;
3227 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3229 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3230 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3231 if(result == GDI_ERROR) {
3232 FIXME("Failed to retrieve vTable\n");
3233 goto end;
3236 if(height > 0) {
3237 for(i = 0; i < recs; i++) {
3238 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3239 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3240 ppem = GET_BE_WORD(vTable[i * 3]);
3242 if(yMax + -yMin == height) {
3243 font->yMax = yMax;
3244 font->yMin = yMin;
3245 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3246 break;
3248 if(yMax + -yMin > height) {
3249 if(--i < 0) {
3250 ppem = 0;
3251 goto end; /* failed */
3253 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3254 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3255 ppem = GET_BE_WORD(vTable[i * 3]);
3256 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3257 break;
3260 if(!font->yMax) {
3261 ppem = 0;
3262 TRACE("ppem not found for height %d\n", height);
3265 end:
3266 HeapFree(GetProcessHeap(), 0, vTable);
3269 return ppem;
3272 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3274 if(font->font_desc.hash != fd->hash) return TRUE;
3275 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3276 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3277 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3278 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3281 static void calc_hash(FONT_DESC *pfd)
3283 DWORD hash = 0, *ptr, two_chars;
3284 WORD *pwc;
3285 unsigned int i;
3287 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3288 hash ^= *ptr;
3289 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3290 hash ^= *ptr;
3291 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3292 two_chars = *ptr;
3293 pwc = (WCHAR *)&two_chars;
3294 if(!*pwc) break;
3295 *pwc = toupperW(*pwc);
3296 pwc++;
3297 *pwc = toupperW(*pwc);
3298 hash ^= two_chars;
3299 if(!*pwc) break;
3301 hash ^= !pfd->can_use_bitmap;
3302 pfd->hash = hash;
3303 return;
3306 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3308 GdiFont *ret;
3309 FONT_DESC fd;
3310 HFONTLIST *hflist;
3311 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3313 fd.lf = *plf;
3314 fd.matrix = *pmat;
3315 fd.can_use_bitmap = can_use_bitmap;
3316 calc_hash(&fd);
3318 /* try the child list */
3319 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3320 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3321 if(!fontcmp(ret, &fd)) {
3322 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3323 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3324 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3325 if(hflist->hfont == hfont)
3326 return ret;
3331 /* try the in-use list */
3332 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3333 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3334 if(!fontcmp(ret, &fd)) {
3335 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3336 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3337 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3338 if(hflist->hfont == hfont)
3339 return ret;
3341 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3342 hflist->hfont = hfont;
3343 list_add_head(&ret->hfontlist, &hflist->entry);
3344 return ret;
3348 /* then the unused list */
3349 font_elem_ptr = list_head(&unused_gdi_font_list);
3350 while(font_elem_ptr) {
3351 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3352 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3353 if(!fontcmp(ret, &fd)) {
3354 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3355 assert(list_empty(&ret->hfontlist));
3356 TRACE("Found %p in unused list\n", ret);
3357 list_remove(&ret->entry);
3358 list_add_head(&gdi_font_list, &ret->entry);
3359 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3360 hflist->hfont = hfont;
3361 list_add_head(&ret->hfontlist, &hflist->entry);
3362 return ret;
3365 return NULL;
3368 static void add_to_cache(GdiFont *font)
3370 static DWORD cache_num = 1;
3372 font->cache_num = cache_num++;
3373 list_add_head(&gdi_font_list, &font->entry);
3376 /*************************************************************
3377 * create_child_font_list
3379 static BOOL create_child_font_list(GdiFont *font)
3381 BOOL ret = FALSE;
3382 SYSTEM_LINKS *font_link;
3383 CHILD_FONT *font_link_entry, *new_child;
3384 FontSubst *psub;
3385 WCHAR* font_name;
3387 psub = get_font_subst(&font_subst_list, font->name, -1);
3388 font_name = psub ? psub->to.name : font->name;
3389 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3391 if(!strcmpiW(font_link->font_name, font_name))
3393 TRACE("found entry in system list\n");
3394 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3396 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3397 new_child->face = font_link_entry->face;
3398 new_child->font = NULL;
3399 list_add_tail(&font->child_fonts, &new_child->entry);
3400 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3402 ret = TRUE;
3403 break;
3407 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3408 * Sans Serif. This is how asian windows get default fallbacks for fonts
3410 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3411 font->charset != OEM_CHARSET &&
3412 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3413 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3415 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3417 TRACE("found entry in default fallback list\n");
3418 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3420 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3421 new_child->face = font_link_entry->face;
3422 new_child->font = NULL;
3423 list_add_tail(&font->child_fonts, &new_child->entry);
3424 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3426 ret = TRUE;
3427 break;
3431 return ret;
3434 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3436 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3438 if (pFT_Set_Charmap)
3440 FT_Int i;
3441 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3443 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3445 for (i = 0; i < ft_face->num_charmaps; i++)
3447 if (ft_face->charmaps[i]->encoding == encoding)
3449 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3450 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3452 switch (ft_face->charmaps[i]->platform_id)
3454 default:
3455 cmap_def = ft_face->charmaps[i];
3456 break;
3457 case 0: /* Apple Unicode */
3458 cmap0 = ft_face->charmaps[i];
3459 break;
3460 case 1: /* Macintosh */
3461 cmap1 = ft_face->charmaps[i];
3462 break;
3463 case 2: /* ISO */
3464 cmap2 = ft_face->charmaps[i];
3465 break;
3466 case 3: /* Microsoft */
3467 cmap3 = ft_face->charmaps[i];
3468 break;
3472 if (cmap3) /* prefer Microsoft cmap table */
3473 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3474 else if (cmap1)
3475 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3476 else if (cmap2)
3477 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3478 else if (cmap0)
3479 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3480 else if (cmap_def)
3481 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3483 return ft_err == FT_Err_Ok;
3486 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3489 /*************************************************************
3490 * WineEngCreateFontInstance
3493 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3495 GdiFont *ret;
3496 Face *face, *best, *best_bitmap;
3497 Family *family, *last_resort_family;
3498 struct list *family_elem_ptr, *face_elem_ptr;
3499 INT height, width = 0;
3500 unsigned int score = 0, new_score;
3501 signed int diff = 0, newdiff;
3502 BOOL bd, it, can_use_bitmap;
3503 LOGFONTW lf;
3504 CHARSETINFO csi;
3505 HFONTLIST *hflist;
3506 FMAT2 dcmat;
3507 FontSubst *psub = NULL;
3509 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3510 lf.lfWidth = abs(lf.lfWidth);
3512 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3514 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3515 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3516 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3517 lf.lfEscapement);
3519 if(dc->GraphicsMode == GM_ADVANCED)
3520 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3521 else
3523 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3524 font scaling abilities. */
3525 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3526 dcmat.eM21 = dcmat.eM12 = 0;
3529 /* Try to avoid not necessary glyph transformations */
3530 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3532 lf.lfHeight *= fabs(dcmat.eM11);
3533 lf.lfWidth *= fabs(dcmat.eM11);
3534 dcmat.eM11 = dcmat.eM22 = 1.0;
3537 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3538 dcmat.eM21, dcmat.eM22);
3540 GDI_CheckNotLock();
3541 EnterCriticalSection( &freetype_cs );
3543 /* check the cache first */
3544 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3545 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3546 LeaveCriticalSection( &freetype_cs );
3547 return ret;
3550 TRACE("not in cache\n");
3551 if(list_empty(&font_list)) /* No fonts installed */
3553 TRACE("No fonts installed\n");
3554 LeaveCriticalSection( &freetype_cs );
3555 return NULL;
3558 ret = alloc_font();
3560 ret->font_desc.matrix = dcmat;
3561 ret->font_desc.lf = lf;
3562 ret->font_desc.can_use_bitmap = can_use_bitmap;
3563 calc_hash(&ret->font_desc);
3564 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3565 hflist->hfont = hfont;
3566 list_add_head(&ret->hfontlist, &hflist->entry);
3568 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3569 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3570 original value lfCharSet. Note this is a special case for
3571 Symbol and doesn't happen at least for "Wingdings*" */
3573 if(!strcmpiW(lf.lfFaceName, SymbolW))
3574 lf.lfCharSet = SYMBOL_CHARSET;
3576 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3577 switch(lf.lfCharSet) {
3578 case DEFAULT_CHARSET:
3579 csi.fs.fsCsb[0] = 0;
3580 break;
3581 default:
3582 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3583 csi.fs.fsCsb[0] = 0;
3584 break;
3588 family = NULL;
3589 if(lf.lfFaceName[0] != '\0') {
3590 SYSTEM_LINKS *font_link;
3591 CHILD_FONT *font_link_entry;
3592 LPWSTR FaceName = lf.lfFaceName;
3595 * Check for a leading '@' this signals that the font is being
3596 * requested in tategaki mode (vertical writing substitution) but
3597 * does not affect the fontface that is to be selected.
3599 if (lf.lfFaceName[0]=='@')
3600 FaceName = &lf.lfFaceName[1];
3602 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3604 if(psub) {
3605 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3606 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3607 if (psub->to.charset != -1)
3608 lf.lfCharSet = psub->to.charset;
3611 /* We want a match on name and charset or just name if
3612 charset was DEFAULT_CHARSET. If the latter then
3613 we fixup the returned charset later in get_nearest_charset
3614 where we'll either use the charset of the current ansi codepage
3615 or if that's unavailable the first charset that the font supports.
3617 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3618 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3619 if (!strcmpiW(family->FamilyName, FaceName) ||
3620 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3622 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3623 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3624 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3625 if(face->scalable || can_use_bitmap)
3626 goto found;
3631 /* Search by full face name. */
3632 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3633 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3634 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3635 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3636 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3637 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3639 if(face->scalable || can_use_bitmap)
3640 goto found_face;
3646 * Try check the SystemLink list first for a replacement font.
3647 * We may find good replacements there.
3649 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3651 if(!strcmpiW(font_link->font_name, FaceName) ||
3652 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3654 TRACE("found entry in system list\n");
3655 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3657 face = font_link_entry->face;
3658 family = face->family;
3659 if(csi.fs.fsCsb[0] &
3660 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3662 if(face->scalable || can_use_bitmap)
3663 goto found;
3670 psub = NULL; /* substitution is no more relevant */
3672 /* If requested charset was DEFAULT_CHARSET then try using charset
3673 corresponding to the current ansi codepage */
3674 if (!csi.fs.fsCsb[0])
3676 INT acp = GetACP();
3677 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3678 FIXME("TCI failed on codepage %d\n", acp);
3679 csi.fs.fsCsb[0] = 0;
3680 } else
3681 lf.lfCharSet = csi.ciCharset;
3684 /* Face families are in the top 4 bits of lfPitchAndFamily,
3685 so mask with 0xF0 before testing */
3687 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3688 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3689 strcpyW(lf.lfFaceName, defFixed);
3690 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3691 strcpyW(lf.lfFaceName, defSerif);
3692 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3693 strcpyW(lf.lfFaceName, defSans);
3694 else
3695 strcpyW(lf.lfFaceName, defSans);
3696 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3697 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3698 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3699 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3700 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3701 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3702 if(face->scalable || can_use_bitmap)
3703 goto found;
3708 last_resort_family = NULL;
3709 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3710 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3711 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3712 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3713 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3714 if(face->scalable)
3715 goto found;
3716 if(can_use_bitmap && !last_resort_family)
3717 last_resort_family = family;
3722 if(last_resort_family) {
3723 family = last_resort_family;
3724 csi.fs.fsCsb[0] = 0;
3725 goto found;
3728 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3729 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3730 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3731 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3732 if(face->scalable) {
3733 csi.fs.fsCsb[0] = 0;
3734 WARN("just using first face for now\n");
3735 goto found;
3737 if(can_use_bitmap && !last_resort_family)
3738 last_resort_family = family;
3741 if(!last_resort_family) {
3742 FIXME("can't find a single appropriate font - bailing\n");
3743 free_font(ret);
3744 LeaveCriticalSection( &freetype_cs );
3745 return NULL;
3748 WARN("could only find a bitmap font - this will probably look awful!\n");
3749 family = last_resort_family;
3750 csi.fs.fsCsb[0] = 0;
3752 found:
3753 it = lf.lfItalic ? 1 : 0;
3754 bd = lf.lfWeight > 550 ? 1 : 0;
3756 height = lf.lfHeight;
3758 face = best = best_bitmap = NULL;
3759 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3761 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3763 BOOL italic, bold;
3765 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3766 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3767 new_score = (italic ^ it) + (bold ^ bd);
3768 if(!best || new_score <= score)
3770 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3771 italic, bold, it, bd);
3772 score = new_score;
3773 best = face;
3774 if(best->scalable && score == 0) break;
3775 if(!best->scalable)
3777 if(height > 0)
3778 newdiff = height - (signed int)(best->size.height);
3779 else
3780 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3781 if(!best_bitmap || new_score < score ||
3782 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3784 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3785 diff = newdiff;
3786 best_bitmap = best;
3787 if(score == 0 && diff == 0) break;
3793 if(best)
3794 face = best->scalable ? best : best_bitmap;
3795 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3796 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3798 found_face:
3799 height = lf.lfHeight;
3801 ret->fs = face->fs;
3803 if(csi.fs.fsCsb[0]) {
3804 ret->charset = lf.lfCharSet;
3805 ret->codepage = csi.ciACP;
3807 else
3808 ret->charset = get_nearest_charset(face, &ret->codepage);
3810 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3811 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3813 ret->aveWidth = height ? lf.lfWidth : 0;
3815 if(!face->scalable) {
3816 /* Windows uses integer scaling factors for bitmap fonts */
3817 INT scale, scaled_height;
3818 GdiFont *cachedfont;
3820 /* FIXME: rotation of bitmap fonts is ignored */
3821 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3822 if (ret->aveWidth)
3823 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3824 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3825 dcmat.eM11 = dcmat.eM22 = 1.0;
3826 /* As we changed the matrix, we need to search the cache for the font again,
3827 * otherwise we might explode the cache. */
3828 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3829 TRACE("Found cached font after non-scalable matrix rescale!\n");
3830 free_font( ret );
3831 LeaveCriticalSection( &freetype_cs );
3832 return cachedfont;
3834 calc_hash(&ret->font_desc);
3836 if (height != 0) height = diff;
3837 height += face->size.height;
3839 scale = (height + face->size.height - 1) / face->size.height;
3840 scaled_height = scale * face->size.height;
3841 /* Only jump to the next height if the difference <= 25% original height */
3842 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3843 /* The jump between unscaled and doubled is delayed by 1 */
3844 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3845 ret->scale_y = scale;
3847 width = face->size.x_ppem >> 6;
3848 height = face->size.y_ppem >> 6;
3850 else
3851 ret->scale_y = 1.0;
3852 TRACE("font scale y: %f\n", ret->scale_y);
3854 ret->ft_face = OpenFontFace(ret, face, width, height);
3856 if (!ret->ft_face)
3858 free_font( ret );
3859 LeaveCriticalSection( &freetype_cs );
3860 return 0;
3863 ret->ntmFlags = face->ntmFlags;
3865 if (ret->charset == SYMBOL_CHARSET &&
3866 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3867 /* No ops */
3869 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3870 /* No ops */
3872 else {
3873 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3876 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3877 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3878 ret->underline = lf.lfUnderline ? 0xff : 0;
3879 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3880 create_child_font_list(ret);
3882 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3884 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3885 if (length != GDI_ERROR)
3887 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3888 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3889 TRACE("Loaded GSUB table of %i bytes\n",length);
3893 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3895 add_to_cache(ret);
3896 LeaveCriticalSection( &freetype_cs );
3897 return ret;
3900 static void dump_gdi_font_list(void)
3902 GdiFont *gdiFont;
3903 struct list *elem_ptr;
3905 TRACE("---------- gdiFont Cache ----------\n");
3906 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3907 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3908 TRACE("gdiFont=%p %s %d\n",
3909 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3912 TRACE("---------- Unused gdiFont Cache ----------\n");
3913 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3914 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3915 TRACE("gdiFont=%p %s %d\n",
3916 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3919 TRACE("---------- Child gdiFont Cache ----------\n");
3920 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3921 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3922 TRACE("gdiFont=%p %s %d\n",
3923 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3927 /*************************************************************
3928 * WineEngDestroyFontInstance
3930 * free the gdiFont associated with this handle
3933 BOOL WineEngDestroyFontInstance(HFONT handle)
3935 GdiFont *gdiFont;
3936 HFONTLIST *hflist;
3937 BOOL ret = FALSE;
3938 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3939 int i = 0;
3941 GDI_CheckNotLock();
3942 EnterCriticalSection( &freetype_cs );
3944 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3946 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3947 while(hfontlist_elem_ptr) {
3948 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3949 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3950 if(hflist->hfont == handle) {
3951 TRACE("removing child font %p from child list\n", gdiFont);
3952 list_remove(&gdiFont->entry);
3953 LeaveCriticalSection( &freetype_cs );
3954 return TRUE;
3959 TRACE("destroying hfont=%p\n", handle);
3960 if(TRACE_ON(font))
3961 dump_gdi_font_list();
3963 font_elem_ptr = list_head(&gdi_font_list);
3964 while(font_elem_ptr) {
3965 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3966 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3968 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3969 while(hfontlist_elem_ptr) {
3970 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3971 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3972 if(hflist->hfont == handle) {
3973 list_remove(&hflist->entry);
3974 HeapFree(GetProcessHeap(), 0, hflist);
3975 ret = TRUE;
3978 if(list_empty(&gdiFont->hfontlist)) {
3979 TRACE("Moving to Unused list\n");
3980 list_remove(&gdiFont->entry);
3981 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3986 font_elem_ptr = list_head(&unused_gdi_font_list);
3987 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3988 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3989 while(font_elem_ptr) {
3990 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3991 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3992 TRACE("freeing %p\n", gdiFont);
3993 list_remove(&gdiFont->entry);
3994 free_font(gdiFont);
3996 LeaveCriticalSection( &freetype_cs );
3997 return ret;
4000 /***************************************************
4001 * create_enum_charset_list
4003 * This function creates charset enumeration list because in DEFAULT_CHARSET
4004 * case, the ANSI codepage's charset takes precedence over other charsets.
4005 * This function works as a filter other than DEFAULT_CHARSET case.
4007 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4009 CHARSETINFO csi;
4010 DWORD n = 0;
4012 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4013 csi.fs.fsCsb[0] != 0) {
4014 list->element[n].mask = csi.fs.fsCsb[0];
4015 list->element[n].charset = csi.ciCharset;
4016 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4017 n++;
4019 else { /* charset is DEFAULT_CHARSET or invalid. */
4020 INT acp, i;
4022 /* Set the current codepage's charset as the first element. */
4023 acp = GetACP();
4024 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4025 csi.fs.fsCsb[0] != 0) {
4026 list->element[n].mask = csi.fs.fsCsb[0];
4027 list->element[n].charset = csi.ciCharset;
4028 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4029 n++;
4032 /* Fill out left elements. */
4033 for (i = 0; i < 32; i++) {
4034 FONTSIGNATURE fs;
4035 fs.fsCsb[0] = 1L << i;
4036 fs.fsCsb[1] = 0;
4037 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4038 continue; /* skip, already added. */
4039 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4040 continue; /* skip, this is an invalid fsCsb bit. */
4042 list->element[n].mask = fs.fsCsb[0];
4043 list->element[n].charset = csi.ciCharset;
4044 list->element[n].name = ElfScriptsW[i];
4045 n++;
4048 list->total = n;
4050 return n;
4053 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4054 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4056 GdiFont *font;
4057 LONG width, height;
4059 if (face->cached_enum_data)
4061 TRACE("Cached\n");
4062 *pelf = face->cached_enum_data->elf;
4063 *pntm = face->cached_enum_data->ntm;
4064 *ptype = face->cached_enum_data->type;
4065 return;
4068 font = alloc_font();
4070 if(face->scalable) {
4071 height = -2048; /* 2048 is the most common em size */
4072 width = 0;
4073 } else {
4074 height = face->size.y_ppem >> 6;
4075 width = face->size.x_ppem >> 6;
4077 font->scale_y = 1.0;
4079 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4081 free_font(font);
4082 return;
4085 font->name = strdupW(face->family->FamilyName);
4086 font->ntmFlags = face->ntmFlags;
4088 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4090 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4092 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4094 lstrcpynW(pelf->elfLogFont.lfFaceName,
4095 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4096 LF_FACESIZE);
4097 lstrcpynW(pelf->elfFullName,
4098 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4099 LF_FULLFACESIZE);
4100 lstrcpynW(pelf->elfStyle,
4101 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4102 LF_FACESIZE);
4104 else
4106 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4108 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4110 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4111 if (face->FullName)
4112 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4113 else
4114 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4115 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4118 pntm->ntmTm.ntmFlags = face->ntmFlags;
4119 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4120 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4121 pntm->ntmFontSig = face->fs;
4123 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4125 pelf->elfLogFont.lfEscapement = 0;
4126 pelf->elfLogFont.lfOrientation = 0;
4127 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4128 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4129 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4130 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4131 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4132 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4133 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4134 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4135 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4136 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4137 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4139 *ptype = 0;
4140 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4141 *ptype |= TRUETYPE_FONTTYPE;
4142 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4143 *ptype |= DEVICE_FONTTYPE;
4144 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4145 *ptype |= RASTER_FONTTYPE;
4147 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4148 if (face->cached_enum_data)
4150 face->cached_enum_data->elf = *pelf;
4151 face->cached_enum_data->ntm = *pntm;
4152 face->cached_enum_data->type = *ptype;
4155 free_font(font);
4158 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4160 struct list *face_elem_ptr;
4162 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4164 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4166 static const WCHAR spaceW[] = { ' ',0 };
4167 WCHAR full_family_name[LF_FULLFACESIZE];
4168 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4170 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4172 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4173 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4174 continue;
4177 strcpyW(full_family_name, family->FamilyName);
4178 strcatW(full_family_name, spaceW);
4179 strcatW(full_family_name, face->StyleName);
4180 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4183 return FALSE;
4186 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4188 static const WCHAR spaceW[] = { ' ',0 };
4189 WCHAR full_family_name[LF_FULLFACESIZE];
4191 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4193 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4195 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4196 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4197 return FALSE;
4200 strcpyW(full_family_name, face->family->FamilyName);
4201 strcatW(full_family_name, spaceW);
4202 strcatW(full_family_name, face->StyleName);
4203 return !strcmpiW(lf->lfFaceName, full_family_name);
4206 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4207 FONTENUMPROCW proc, LPARAM lparam)
4209 ENUMLOGFONTEXW elf;
4210 NEWTEXTMETRICEXW ntm;
4211 DWORD type = 0;
4212 int i;
4214 GetEnumStructs(face, &elf, &ntm, &type);
4215 for(i = 0; i < list->total; i++) {
4216 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4217 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4218 strcpyW(elf.elfScript, OEM_DOSW);
4219 i = 32; /* break out of loop */
4220 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4221 continue;
4222 else {
4223 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4224 if(list->element[i].name)
4225 strcpyW(elf.elfScript, list->element[i].name);
4226 else
4227 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4229 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4230 debugstr_w(elf.elfLogFont.lfFaceName),
4231 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4232 list->element[i].charset, type, debugstr_w(elf.elfScript),
4233 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4234 ntm.ntmTm.ntmFlags);
4235 /* release section before callback (FIXME) */
4236 LeaveCriticalSection( &freetype_cs );
4237 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4238 EnterCriticalSection( &freetype_cs );
4240 return TRUE;
4243 /*************************************************************
4244 * WineEngEnumFonts
4247 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4249 Family *family;
4250 Face *face;
4251 struct list *family_elem_ptr, *face_elem_ptr;
4252 LOGFONTW lf;
4253 struct enum_charset_list enum_charsets;
4255 if (!plf)
4257 lf.lfCharSet = DEFAULT_CHARSET;
4258 lf.lfPitchAndFamily = 0;
4259 lf.lfFaceName[0] = 0;
4260 plf = &lf;
4263 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4265 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4267 GDI_CheckNotLock();
4268 EnterCriticalSection( &freetype_cs );
4269 if(plf->lfFaceName[0]) {
4270 FontSubst *psub;
4271 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4273 if(psub) {
4274 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4275 debugstr_w(psub->to.name));
4276 lf = *plf;
4277 strcpyW(lf.lfFaceName, psub->to.name);
4278 plf = &lf;
4281 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4282 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4283 if(family_matches(family, plf)) {
4284 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4285 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4286 if (!face_matches(face, plf)) continue;
4287 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4291 } else {
4292 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4293 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4294 face_elem_ptr = list_head(&family->faces);
4295 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4296 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4299 LeaveCriticalSection( &freetype_cs );
4300 return 1;
4303 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4305 pt->x.value = vec->x >> 6;
4306 pt->x.fract = (vec->x & 0x3f) << 10;
4307 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4308 pt->y.value = vec->y >> 6;
4309 pt->y.fract = (vec->y & 0x3f) << 10;
4310 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4311 return;
4314 /***************************************************
4315 * According to the MSDN documentation on WideCharToMultiByte,
4316 * certain codepages cannot set the default_used parameter.
4317 * This returns TRUE if the codepage can set that parameter, false else
4318 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4320 static BOOL codepage_sets_default_used(UINT codepage)
4322 switch (codepage)
4324 case CP_UTF7:
4325 case CP_UTF8:
4326 case CP_SYMBOL:
4327 return FALSE;
4328 default:
4329 return TRUE;
4334 * GSUB Table handling functions
4337 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4339 const GSUB_CoverageFormat1* cf1;
4341 cf1 = table;
4343 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4345 int count = GET_BE_WORD(cf1->GlyphCount);
4346 int i;
4347 TRACE("Coverage Format 1, %i glyphs\n",count);
4348 for (i = 0; i < count; i++)
4349 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4350 return i;
4351 return -1;
4353 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4355 const GSUB_CoverageFormat2* cf2;
4356 int i;
4357 int count;
4358 cf2 = (const GSUB_CoverageFormat2*)cf1;
4360 count = GET_BE_WORD(cf2->RangeCount);
4361 TRACE("Coverage Format 2, %i ranges\n",count);
4362 for (i = 0; i < count; i++)
4364 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4365 return -1;
4366 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4367 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4369 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4370 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4373 return -1;
4375 else
4376 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4378 return -1;
4381 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4383 const GSUB_ScriptList *script;
4384 const GSUB_Script *deflt = NULL;
4385 int i;
4386 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4388 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4389 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4391 const GSUB_Script *scr;
4392 int offset;
4394 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4395 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4397 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4398 return scr;
4399 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4400 deflt = scr;
4402 return deflt;
4405 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4407 int i;
4408 int offset;
4409 const GSUB_LangSys *Lang;
4411 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4413 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4415 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4416 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4418 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4419 return Lang;
4421 offset = GET_BE_WORD(script->DefaultLangSys);
4422 if (offset)
4424 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4425 return Lang;
4427 return NULL;
4430 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4432 int i;
4433 const GSUB_FeatureList *feature;
4434 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4436 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4437 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4439 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4440 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4442 const GSUB_Feature *feat;
4443 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4444 return feat;
4447 return NULL;
4450 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4452 int i;
4453 int offset;
4454 const GSUB_LookupList *lookup;
4455 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4457 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4458 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4460 const GSUB_LookupTable *look;
4461 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4462 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4463 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4464 if (GET_BE_WORD(look->LookupType) != 1)
4465 FIXME("We only handle SubType 1\n");
4466 else
4468 int j;
4470 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4472 const GSUB_SingleSubstFormat1 *ssf1;
4473 offset = GET_BE_WORD(look->SubTable[j]);
4474 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4475 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4477 int offset = GET_BE_WORD(ssf1->Coverage);
4478 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4479 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4481 TRACE(" Glyph 0x%x ->",glyph);
4482 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4483 TRACE(" 0x%x\n",glyph);
4486 else
4488 const GSUB_SingleSubstFormat2 *ssf2;
4489 INT index;
4490 INT offset;
4492 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4493 offset = GET_BE_WORD(ssf1->Coverage);
4494 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4495 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4496 TRACE(" Coverage index %i\n",index);
4497 if (index != -1)
4499 TRACE(" Glyph is 0x%x ->",glyph);
4500 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4501 TRACE("0x%x\n",glyph);
4507 return glyph;
4510 static const char* get_opentype_script(const GdiFont *font)
4513 * I am not sure if this is the correct way to generate our script tag
4516 switch (font->charset)
4518 case ANSI_CHARSET: return "latn";
4519 case BALTIC_CHARSET: return "latn"; /* ?? */
4520 case CHINESEBIG5_CHARSET: return "hani";
4521 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4522 case GB2312_CHARSET: return "hani";
4523 case GREEK_CHARSET: return "grek";
4524 case HANGUL_CHARSET: return "hang";
4525 case RUSSIAN_CHARSET: return "cyrl";
4526 case SHIFTJIS_CHARSET: return "kana";
4527 case TURKISH_CHARSET: return "latn"; /* ?? */
4528 case VIETNAMESE_CHARSET: return "latn";
4529 case JOHAB_CHARSET: return "latn"; /* ?? */
4530 case ARABIC_CHARSET: return "arab";
4531 case HEBREW_CHARSET: return "hebr";
4532 case THAI_CHARSET: return "thai";
4533 default: return "latn";
4537 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4539 const GSUB_Header *header;
4540 const GSUB_Script *script;
4541 const GSUB_LangSys *language;
4542 const GSUB_Feature *feature;
4544 if (!font->GSUB_Table)
4545 return glyph;
4547 header = font->GSUB_Table;
4549 script = GSUB_get_script_table(header, get_opentype_script(font));
4550 if (!script)
4552 TRACE("Script not found\n");
4553 return glyph;
4555 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4556 if (!language)
4558 TRACE("Language not found\n");
4559 return glyph;
4561 feature = GSUB_get_feature(header, language, "vrt2");
4562 if (!feature)
4563 feature = GSUB_get_feature(header, language, "vert");
4564 if (!feature)
4566 TRACE("vrt2/vert feature not found\n");
4567 return glyph;
4569 return GSUB_apply_feature(header, feature, glyph);
4572 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4574 FT_UInt glyphId;
4576 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4577 WCHAR wc = (WCHAR)glyph;
4578 BOOL default_used;
4579 BOOL *default_used_pointer;
4580 FT_UInt ret;
4581 char buf;
4582 default_used_pointer = NULL;
4583 default_used = FALSE;
4584 if (codepage_sets_default_used(font->codepage))
4585 default_used_pointer = &default_used;
4586 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4587 ret = 0;
4588 else
4589 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4590 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4591 return get_GSUB_vert_glyph(font,ret);
4594 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4596 if (glyph < 0x100) glyph += 0xf000;
4597 /* there is a number of old pre-Unicode "broken" TTFs, which
4598 do have symbols at U+00XX instead of U+f0XX */
4599 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4600 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4602 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4604 return get_GSUB_vert_glyph(font,glyphId);
4607 /*************************************************************
4608 * WineEngGetGlyphIndices
4611 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4612 LPWORD pgi, DWORD flags)
4614 int i;
4615 WORD default_char;
4616 BOOL got_default = FALSE;
4618 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4620 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4621 got_default = TRUE;
4624 for(i = 0; i < count; i++)
4626 pgi[i] = get_glyph_index(font, lpstr[i]);
4627 if (pgi[i] == 0)
4629 if (!got_default)
4631 if (FT_IS_SFNT(font->ft_face))
4633 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4634 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4636 else
4638 TEXTMETRICW textm;
4639 WineEngGetTextMetrics(font, &textm);
4640 default_char = textm.tmDefaultChar;
4642 got_default = TRUE;
4644 pgi[i] = default_char;
4647 return count;
4650 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4652 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4653 return !memcmp(matrix, &identity, sizeof(FMAT2));
4656 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4658 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4659 return !memcmp(matrix, &identity, sizeof(MAT2));
4662 /*************************************************************
4663 * WineEngGetGlyphOutline
4665 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4666 * except that the first parameter is the HWINEENGFONT of the font in
4667 * question rather than an HDC.
4670 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4671 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4672 const MAT2* lpmat)
4674 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4675 FT_Face ft_face = incoming_font->ft_face;
4676 GdiFont *font = incoming_font;
4677 FT_UInt glyph_index;
4678 DWORD width, height, pitch, needed = 0;
4679 FT_Bitmap ft_bitmap;
4680 FT_Error err;
4681 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4682 FT_Angle angle = 0;
4683 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4684 double widthRatio = 1.0;
4685 FT_Matrix transMat = identityMat;
4686 FT_Matrix transMatUnrotated;
4687 BOOL needsTransform = FALSE;
4688 BOOL tategaki = (font->GSUB_Table != NULL);
4689 UINT original_index;
4691 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4692 buflen, buf, lpmat);
4694 TRACE("font transform %f %f %f %f\n",
4695 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4696 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4698 GDI_CheckNotLock();
4699 EnterCriticalSection( &freetype_cs );
4701 if(format & GGO_GLYPH_INDEX) {
4702 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4703 original_index = glyph;
4704 format &= ~GGO_GLYPH_INDEX;
4705 } else {
4706 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4707 ft_face = font->ft_face;
4708 original_index = glyph_index;
4711 if(format & GGO_UNHINTED) {
4712 load_flags |= FT_LOAD_NO_HINTING;
4713 format &= ~GGO_UNHINTED;
4716 /* tategaki never appears to happen to lower glyph index */
4717 if (glyph_index < TATEGAKI_LOWER_BOUND )
4718 tategaki = FALSE;
4720 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4721 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4722 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4723 font->gmsize * sizeof(GM*));
4724 } else {
4725 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4726 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4728 *lpgm = FONT_GM(font,original_index)->gm;
4729 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4730 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4731 lpgm->gmCellIncX, lpgm->gmCellIncY);
4732 LeaveCriticalSection( &freetype_cs );
4733 return 1; /* FIXME */
4737 if (!font->gm[original_index / GM_BLOCK_SIZE])
4738 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4740 /* Scaling factor */
4741 if (font->aveWidth)
4743 TEXTMETRICW tm;
4745 WineEngGetTextMetrics(font, &tm);
4747 widthRatio = (double)font->aveWidth;
4748 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4750 else
4751 widthRatio = font->scale_y;
4753 /* Scaling transform */
4754 if (widthRatio != 1.0 || font->scale_y != 1.0)
4756 FT_Matrix scaleMat;
4757 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4758 scaleMat.xy = 0;
4759 scaleMat.yx = 0;
4760 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4762 pFT_Matrix_Multiply(&scaleMat, &transMat);
4763 needsTransform = TRUE;
4766 /* Slant transform */
4767 if (font->fake_italic) {
4768 FT_Matrix slantMat;
4770 slantMat.xx = (1 << 16);
4771 slantMat.xy = ((1 << 16) >> 2);
4772 slantMat.yx = 0;
4773 slantMat.yy = (1 << 16);
4774 pFT_Matrix_Multiply(&slantMat, &transMat);
4775 needsTransform = TRUE;
4778 /* Rotation transform */
4779 transMatUnrotated = transMat;
4780 if(font->orientation && !tategaki) {
4781 FT_Matrix rotationMat;
4782 FT_Vector vecAngle;
4783 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4784 pFT_Vector_Unit(&vecAngle, angle);
4785 rotationMat.xx = vecAngle.x;
4786 rotationMat.xy = -vecAngle.y;
4787 rotationMat.yx = -rotationMat.xy;
4788 rotationMat.yy = rotationMat.xx;
4790 pFT_Matrix_Multiply(&rotationMat, &transMat);
4791 needsTransform = TRUE;
4794 /* World transform */
4795 if (!is_identity_FMAT2(&font->font_desc.matrix))
4797 FT_Matrix worldMat;
4798 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4799 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4800 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4801 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4802 pFT_Matrix_Multiply(&worldMat, &transMat);
4803 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4804 needsTransform = TRUE;
4807 /* Extra transformation specified by caller */
4808 if (!is_identity_MAT2(lpmat))
4810 FT_Matrix extraMat;
4811 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4812 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4813 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4814 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4815 pFT_Matrix_Multiply(&extraMat, &transMat);
4816 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4817 needsTransform = TRUE;
4820 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4821 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4822 format == GGO_GRAY8_BITMAP))
4824 load_flags |= FT_LOAD_NO_BITMAP;
4827 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4829 if(err) {
4830 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4831 LeaveCriticalSection( &freetype_cs );
4832 return GDI_ERROR;
4835 if(!needsTransform) {
4836 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4837 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4838 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4840 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4841 bottom = (ft_face->glyph->metrics.horiBearingY -
4842 ft_face->glyph->metrics.height) & -64;
4843 lpgm->gmCellIncX = adv;
4844 lpgm->gmCellIncY = 0;
4845 } else {
4846 INT xc, yc;
4847 FT_Vector vec;
4849 left = right = 0;
4851 for(xc = 0; xc < 2; xc++) {
4852 for(yc = 0; yc < 2; yc++) {
4853 vec.x = (ft_face->glyph->metrics.horiBearingX +
4854 xc * ft_face->glyph->metrics.width);
4855 vec.y = ft_face->glyph->metrics.horiBearingY -
4856 yc * ft_face->glyph->metrics.height;
4857 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4858 pFT_Vector_Transform(&vec, &transMat);
4859 if(xc == 0 && yc == 0) {
4860 left = right = vec.x;
4861 top = bottom = vec.y;
4862 } else {
4863 if(vec.x < left) left = vec.x;
4864 else if(vec.x > right) right = vec.x;
4865 if(vec.y < bottom) bottom = vec.y;
4866 else if(vec.y > top) top = vec.y;
4870 left = left & -64;
4871 right = (right + 63) & -64;
4872 bottom = bottom & -64;
4873 top = (top + 63) & -64;
4875 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4876 vec.x = ft_face->glyph->metrics.horiAdvance;
4877 vec.y = 0;
4878 pFT_Vector_Transform(&vec, &transMat);
4879 lpgm->gmCellIncX = (vec.x+63) >> 6;
4880 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4882 vec.x = ft_face->glyph->metrics.horiAdvance;
4883 vec.y = 0;
4884 pFT_Vector_Transform(&vec, &transMatUnrotated);
4885 adv = (vec.x+63) >> 6;
4888 lsb = left >> 6;
4889 bbx = (right - left) >> 6;
4890 lpgm->gmBlackBoxX = (right - left) >> 6;
4891 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4892 lpgm->gmptGlyphOrigin.x = left >> 6;
4893 lpgm->gmptGlyphOrigin.y = top >> 6;
4895 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4896 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4897 lpgm->gmCellIncX, lpgm->gmCellIncY);
4899 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4900 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4902 FONT_GM(font,original_index)->gm = *lpgm;
4903 FONT_GM(font,original_index)->adv = adv;
4904 FONT_GM(font,original_index)->lsb = lsb;
4905 FONT_GM(font,original_index)->bbx = bbx;
4906 FONT_GM(font,original_index)->init = TRUE;
4909 if(format == GGO_METRICS)
4911 LeaveCriticalSection( &freetype_cs );
4912 return 1; /* FIXME */
4915 if(ft_face->glyph->format != ft_glyph_format_outline &&
4916 (format == GGO_NATIVE || format == GGO_BEZIER ||
4917 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4918 format == GGO_GRAY8_BITMAP))
4920 TRACE("loaded a bitmap\n");
4921 LeaveCriticalSection( &freetype_cs );
4922 return GDI_ERROR;
4925 switch(format) {
4926 case GGO_BITMAP:
4927 width = lpgm->gmBlackBoxX;
4928 height = lpgm->gmBlackBoxY;
4929 pitch = ((width + 31) >> 5) << 2;
4930 needed = pitch * height;
4932 if(!buf || !buflen) break;
4934 switch(ft_face->glyph->format) {
4935 case ft_glyph_format_bitmap:
4937 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4938 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4939 INT h = ft_face->glyph->bitmap.rows;
4940 while(h--) {
4941 memcpy(dst, src, w);
4942 src += ft_face->glyph->bitmap.pitch;
4943 dst += pitch;
4945 break;
4948 case ft_glyph_format_outline:
4949 ft_bitmap.width = width;
4950 ft_bitmap.rows = height;
4951 ft_bitmap.pitch = pitch;
4952 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4953 ft_bitmap.buffer = buf;
4955 if(needsTransform)
4956 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4958 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4960 /* Note: FreeType will only set 'black' bits for us. */
4961 memset(buf, 0, needed);
4962 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4963 break;
4965 default:
4966 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4967 LeaveCriticalSection( &freetype_cs );
4968 return GDI_ERROR;
4970 break;
4972 case GGO_GRAY2_BITMAP:
4973 case GGO_GRAY4_BITMAP:
4974 case GGO_GRAY8_BITMAP:
4975 case WINE_GGO_GRAY16_BITMAP:
4977 unsigned int mult, row, col;
4978 BYTE *start, *ptr;
4980 width = lpgm->gmBlackBoxX;
4981 height = lpgm->gmBlackBoxY;
4982 pitch = (width + 3) / 4 * 4;
4983 needed = pitch * height;
4985 if(!buf || !buflen) break;
4987 switch(ft_face->glyph->format) {
4988 case ft_glyph_format_bitmap:
4990 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4991 INT h = ft_face->glyph->bitmap.rows;
4992 INT x;
4993 memset( buf, 0, needed );
4994 while(h--) {
4995 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4996 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4997 src += ft_face->glyph->bitmap.pitch;
4998 dst += pitch;
5000 LeaveCriticalSection( &freetype_cs );
5001 return needed;
5003 case ft_glyph_format_outline:
5005 ft_bitmap.width = width;
5006 ft_bitmap.rows = height;
5007 ft_bitmap.pitch = pitch;
5008 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5009 ft_bitmap.buffer = buf;
5011 if(needsTransform)
5012 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5014 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5016 memset(ft_bitmap.buffer, 0, buflen);
5018 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5020 if(format == GGO_GRAY2_BITMAP)
5021 mult = 4;
5022 else if(format == GGO_GRAY4_BITMAP)
5023 mult = 16;
5024 else if(format == GGO_GRAY8_BITMAP)
5025 mult = 64;
5026 else /* format == WINE_GGO_GRAY16_BITMAP */
5028 LeaveCriticalSection( &freetype_cs );
5029 return needed;
5031 break;
5033 default:
5034 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5035 LeaveCriticalSection( &freetype_cs );
5036 return GDI_ERROR;
5039 start = buf;
5040 for(row = 0; row < height; row++) {
5041 ptr = start;
5042 for(col = 0; col < width; col++, ptr++) {
5043 *ptr = (((int)*ptr) * mult + 128) / 256;
5045 start += pitch;
5047 break;
5050 case WINE_GGO_HRGB_BITMAP:
5051 case WINE_GGO_HBGR_BITMAP:
5052 case WINE_GGO_VRGB_BITMAP:
5053 case WINE_GGO_VBGR_BITMAP:
5054 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5056 switch (ft_face->glyph->format)
5058 case FT_GLYPH_FORMAT_BITMAP:
5060 BYTE *src, *dst;
5061 INT src_pitch, x;
5063 width = lpgm->gmBlackBoxX;
5064 height = lpgm->gmBlackBoxY;
5065 pitch = width * 4;
5066 needed = pitch * height;
5068 if (!buf || !buflen) break;
5070 memset(buf, 0, buflen);
5071 dst = buf;
5072 src = ft_face->glyph->bitmap.buffer;
5073 src_pitch = ft_face->glyph->bitmap.pitch;
5075 height = min( height, ft_face->glyph->bitmap.rows );
5076 while ( height-- )
5078 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5080 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5081 ((unsigned int *)dst)[x] = ~0u;
5083 src += src_pitch;
5084 dst += pitch;
5087 break;
5090 case FT_GLYPH_FORMAT_OUTLINE:
5092 unsigned int *dst;
5093 BYTE *src;
5094 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5095 INT x_shift, y_shift;
5096 BOOL rgb;
5097 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5098 FT_Render_Mode render_mode =
5099 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5100 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5102 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5104 if ( render_mode == FT_RENDER_MODE_LCD)
5106 lpgm->gmBlackBoxX += 2;
5107 lpgm->gmptGlyphOrigin.x -= 1;
5109 else
5111 lpgm->gmBlackBoxY += 2;
5112 lpgm->gmptGlyphOrigin.y += 1;
5116 width = lpgm->gmBlackBoxX;
5117 height = lpgm->gmBlackBoxY;
5118 pitch = width * 4;
5119 needed = pitch * height;
5121 if (!buf || !buflen) break;
5123 memset(buf, 0, buflen);
5124 dst = buf;
5125 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5127 if ( needsTransform )
5128 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5130 if ( pFT_Library_SetLcdFilter )
5131 pFT_Library_SetLcdFilter( library, lcdfilter );
5132 pFT_Render_Glyph (ft_face->glyph, render_mode);
5134 src = ft_face->glyph->bitmap.buffer;
5135 src_pitch = ft_face->glyph->bitmap.pitch;
5136 src_width = ft_face->glyph->bitmap.width;
5137 src_height = ft_face->glyph->bitmap.rows;
5139 if ( render_mode == FT_RENDER_MODE_LCD)
5141 rgb_interval = 1;
5142 hmul = 3;
5143 vmul = 1;
5145 else
5147 rgb_interval = src_pitch;
5148 hmul = 1;
5149 vmul = 3;
5152 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5153 if ( x_shift < 0 ) x_shift = 0;
5154 if ( x_shift + (src_width / hmul) > width )
5155 x_shift = width - (src_width / hmul);
5157 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5158 if ( y_shift < 0 ) y_shift = 0;
5159 if ( y_shift + (src_height / vmul) > height )
5160 y_shift = height - (src_height / vmul);
5162 dst += x_shift + y_shift * ( pitch / 4 );
5163 while ( src_height )
5165 for ( x = 0; x < src_width / hmul; x++ )
5167 if ( rgb )
5169 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5170 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5171 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5172 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5174 else
5176 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5177 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5178 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5179 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5182 src += src_pitch * vmul;
5183 dst += pitch / 4;
5184 src_height -= vmul;
5187 break;
5190 default:
5191 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5192 LeaveCriticalSection ( &freetype_cs );
5193 return GDI_ERROR;
5196 break;
5198 #else
5199 LeaveCriticalSection( &freetype_cs );
5200 return GDI_ERROR;
5201 #endif
5203 case GGO_NATIVE:
5205 int contour, point = 0, first_pt;
5206 FT_Outline *outline = &ft_face->glyph->outline;
5207 TTPOLYGONHEADER *pph;
5208 TTPOLYCURVE *ppc;
5209 DWORD pph_start, cpfx, type;
5211 if(buflen == 0) buf = NULL;
5213 if (needsTransform && buf) {
5214 pFT_Outline_Transform(outline, &transMat);
5217 for(contour = 0; contour < outline->n_contours; contour++) {
5218 pph_start = needed;
5219 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5220 first_pt = point;
5221 if(buf) {
5222 pph->dwType = TT_POLYGON_TYPE;
5223 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5225 needed += sizeof(*pph);
5226 point++;
5227 while(point <= outline->contours[contour]) {
5228 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5229 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5230 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5231 cpfx = 0;
5232 do {
5233 if(buf)
5234 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5235 cpfx++;
5236 point++;
5237 } while(point <= outline->contours[contour] &&
5238 (outline->tags[point] & FT_Curve_Tag_On) ==
5239 (outline->tags[point-1] & FT_Curve_Tag_On));
5240 /* At the end of a contour Windows adds the start point, but
5241 only for Beziers */
5242 if(point > outline->contours[contour] &&
5243 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5244 if(buf)
5245 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5246 cpfx++;
5247 } else if(point <= outline->contours[contour] &&
5248 outline->tags[point] & FT_Curve_Tag_On) {
5249 /* add closing pt for bezier */
5250 if(buf)
5251 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5252 cpfx++;
5253 point++;
5255 if(buf) {
5256 ppc->wType = type;
5257 ppc->cpfx = cpfx;
5259 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5261 if(buf)
5262 pph->cb = needed - pph_start;
5264 break;
5266 case GGO_BEZIER:
5268 /* Convert the quadratic Beziers to cubic Beziers.
5269 The parametric eqn for a cubic Bezier is, from PLRM:
5270 r(t) = at^3 + bt^2 + ct + r0
5271 with the control points:
5272 r1 = r0 + c/3
5273 r2 = r1 + (c + b)/3
5274 r3 = r0 + c + b + a
5276 A quadratic Bezier has the form:
5277 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5279 So equating powers of t leads to:
5280 r1 = 2/3 p1 + 1/3 p0
5281 r2 = 2/3 p1 + 1/3 p2
5282 and of course r0 = p0, r3 = p2
5285 int contour, point = 0, first_pt;
5286 FT_Outline *outline = &ft_face->glyph->outline;
5287 TTPOLYGONHEADER *pph;
5288 TTPOLYCURVE *ppc;
5289 DWORD pph_start, cpfx, type;
5290 FT_Vector cubic_control[4];
5291 if(buflen == 0) buf = NULL;
5293 if (needsTransform && buf) {
5294 pFT_Outline_Transform(outline, &transMat);
5297 for(contour = 0; contour < outline->n_contours; contour++) {
5298 pph_start = needed;
5299 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5300 first_pt = point;
5301 if(buf) {
5302 pph->dwType = TT_POLYGON_TYPE;
5303 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5305 needed += sizeof(*pph);
5306 point++;
5307 while(point <= outline->contours[contour]) {
5308 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5309 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5310 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5311 cpfx = 0;
5312 do {
5313 if(type == TT_PRIM_LINE) {
5314 if(buf)
5315 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5316 cpfx++;
5317 point++;
5318 } else {
5319 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5320 so cpfx = 3n */
5322 /* FIXME: Possible optimization in endpoint calculation
5323 if there are two consecutive curves */
5324 cubic_control[0] = outline->points[point-1];
5325 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5326 cubic_control[0].x += outline->points[point].x + 1;
5327 cubic_control[0].y += outline->points[point].y + 1;
5328 cubic_control[0].x >>= 1;
5329 cubic_control[0].y >>= 1;
5331 if(point+1 > outline->contours[contour])
5332 cubic_control[3] = outline->points[first_pt];
5333 else {
5334 cubic_control[3] = outline->points[point+1];
5335 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5336 cubic_control[3].x += outline->points[point].x + 1;
5337 cubic_control[3].y += outline->points[point].y + 1;
5338 cubic_control[3].x >>= 1;
5339 cubic_control[3].y >>= 1;
5342 /* r1 = 1/3 p0 + 2/3 p1
5343 r2 = 1/3 p2 + 2/3 p1 */
5344 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5345 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5346 cubic_control[2] = cubic_control[1];
5347 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5348 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5349 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5350 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5351 if(buf) {
5352 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5353 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5354 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5356 cpfx += 3;
5357 point++;
5359 } while(point <= outline->contours[contour] &&
5360 (outline->tags[point] & FT_Curve_Tag_On) ==
5361 (outline->tags[point-1] & FT_Curve_Tag_On));
5362 /* At the end of a contour Windows adds the start point,
5363 but only for Beziers and we've already done that.
5365 if(point <= outline->contours[contour] &&
5366 outline->tags[point] & FT_Curve_Tag_On) {
5367 /* This is the closing pt of a bezier, but we've already
5368 added it, so just inc point and carry on */
5369 point++;
5371 if(buf) {
5372 ppc->wType = type;
5373 ppc->cpfx = cpfx;
5375 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5377 if(buf)
5378 pph->cb = needed - pph_start;
5380 break;
5383 default:
5384 FIXME("Unsupported format %d\n", format);
5385 LeaveCriticalSection( &freetype_cs );
5386 return GDI_ERROR;
5388 LeaveCriticalSection( &freetype_cs );
5389 return needed;
5392 static BOOL get_bitmap_text_metrics(GdiFont *font)
5394 FT_Face ft_face = font->ft_face;
5395 #ifdef HAVE_FREETYPE_FTWINFNT_H
5396 FT_WinFNT_HeaderRec winfnt_header;
5397 #endif
5398 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5399 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5400 font->potm->otmSize = size;
5402 #define TM font->potm->otmTextMetrics
5403 #ifdef HAVE_FREETYPE_FTWINFNT_H
5404 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5406 TM.tmHeight = winfnt_header.pixel_height;
5407 TM.tmAscent = winfnt_header.ascent;
5408 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5409 TM.tmInternalLeading = winfnt_header.internal_leading;
5410 TM.tmExternalLeading = winfnt_header.external_leading;
5411 TM.tmAveCharWidth = winfnt_header.avg_width;
5412 TM.tmMaxCharWidth = winfnt_header.max_width;
5413 TM.tmWeight = winfnt_header.weight;
5414 TM.tmOverhang = 0;
5415 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5416 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5417 TM.tmFirstChar = winfnt_header.first_char;
5418 TM.tmLastChar = winfnt_header.last_char;
5419 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5420 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5421 TM.tmItalic = winfnt_header.italic;
5422 TM.tmUnderlined = font->underline;
5423 TM.tmStruckOut = font->strikeout;
5424 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5425 TM.tmCharSet = winfnt_header.charset;
5427 else
5428 #endif
5430 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5431 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5432 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5433 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5434 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5435 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5436 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5437 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5438 TM.tmOverhang = 0;
5439 TM.tmDigitizedAspectX = 96; /* FIXME */
5440 TM.tmDigitizedAspectY = 96; /* FIXME */
5441 TM.tmFirstChar = 1;
5442 TM.tmLastChar = 255;
5443 TM.tmDefaultChar = 32;
5444 TM.tmBreakChar = 32;
5445 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5446 TM.tmUnderlined = font->underline;
5447 TM.tmStruckOut = font->strikeout;
5448 /* NB inverted meaning of TMPF_FIXED_PITCH */
5449 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5450 TM.tmCharSet = font->charset;
5452 #undef TM
5454 return TRUE;
5458 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5460 double scale_x, scale_y;
5462 if (font->aveWidth)
5464 scale_x = (double)font->aveWidth;
5465 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5467 else
5468 scale_x = font->scale_y;
5470 scale_x *= fabs(font->font_desc.matrix.eM11);
5471 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5473 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5474 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5476 SCALE_Y(ptm->tmHeight);
5477 SCALE_Y(ptm->tmAscent);
5478 SCALE_Y(ptm->tmDescent);
5479 SCALE_Y(ptm->tmInternalLeading);
5480 SCALE_Y(ptm->tmExternalLeading);
5481 SCALE_Y(ptm->tmOverhang);
5483 SCALE_X(ptm->tmAveCharWidth);
5484 SCALE_X(ptm->tmMaxCharWidth);
5486 #undef SCALE_X
5487 #undef SCALE_Y
5490 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5492 double scale_x, scale_y;
5494 if (font->aveWidth)
5496 scale_x = (double)font->aveWidth;
5497 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5499 else
5500 scale_x = font->scale_y;
5502 scale_x *= fabs(font->font_desc.matrix.eM11);
5503 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5505 scale_font_metrics(font, &potm->otmTextMetrics);
5507 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5508 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5510 SCALE_Y(potm->otmAscent);
5511 SCALE_Y(potm->otmDescent);
5512 SCALE_Y(potm->otmLineGap);
5513 SCALE_Y(potm->otmsCapEmHeight);
5514 SCALE_Y(potm->otmsXHeight);
5515 SCALE_Y(potm->otmrcFontBox.top);
5516 SCALE_Y(potm->otmrcFontBox.bottom);
5517 SCALE_X(potm->otmrcFontBox.left);
5518 SCALE_X(potm->otmrcFontBox.right);
5519 SCALE_Y(potm->otmMacAscent);
5520 SCALE_Y(potm->otmMacDescent);
5521 SCALE_Y(potm->otmMacLineGap);
5522 SCALE_X(potm->otmptSubscriptSize.x);
5523 SCALE_Y(potm->otmptSubscriptSize.y);
5524 SCALE_X(potm->otmptSubscriptOffset.x);
5525 SCALE_Y(potm->otmptSubscriptOffset.y);
5526 SCALE_X(potm->otmptSuperscriptSize.x);
5527 SCALE_Y(potm->otmptSuperscriptSize.y);
5528 SCALE_X(potm->otmptSuperscriptOffset.x);
5529 SCALE_Y(potm->otmptSuperscriptOffset.y);
5530 SCALE_Y(potm->otmsStrikeoutSize);
5531 SCALE_Y(potm->otmsStrikeoutPosition);
5532 SCALE_Y(potm->otmsUnderscoreSize);
5533 SCALE_Y(potm->otmsUnderscorePosition);
5535 #undef SCALE_X
5536 #undef SCALE_Y
5539 /*************************************************************
5540 * WineEngGetTextMetrics
5543 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5545 GDI_CheckNotLock();
5546 EnterCriticalSection( &freetype_cs );
5547 if(!font->potm) {
5548 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5549 if(!get_bitmap_text_metrics(font))
5551 LeaveCriticalSection( &freetype_cs );
5552 return FALSE;
5555 /* Make sure that the font has sane width/height ratio */
5556 if (font->aveWidth)
5558 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5560 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5561 font->aveWidth = 0;
5566 *ptm = font->potm->otmTextMetrics;
5567 scale_font_metrics(font, ptm);
5568 LeaveCriticalSection( &freetype_cs );
5569 return TRUE;
5572 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5574 int i;
5576 for(i = 0; i < ft_face->num_charmaps; i++)
5578 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5579 return TRUE;
5581 return FALSE;
5584 /*************************************************************
5585 * WineEngGetOutlineTextMetrics
5588 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5589 OUTLINETEXTMETRICW *potm)
5591 FT_Face ft_face = font->ft_face;
5592 UINT needed, lenfam, lensty, ret;
5593 TT_OS2 *pOS2;
5594 TT_HoriHeader *pHori;
5595 TT_Postscript *pPost;
5596 FT_Fixed x_scale, y_scale;
5597 WCHAR *family_nameW, *style_nameW;
5598 static const WCHAR spaceW[] = {' ', '\0'};
5599 char *cp;
5600 INT ascent, descent;
5602 TRACE("font=%p\n", font);
5604 if(!FT_IS_SCALABLE(ft_face))
5605 return 0;
5607 GDI_CheckNotLock();
5608 EnterCriticalSection( &freetype_cs );
5610 if(font->potm) {
5611 if(cbSize >= font->potm->otmSize)
5613 memcpy(potm, font->potm, font->potm->otmSize);
5614 scale_outline_font_metrics(font, potm);
5616 LeaveCriticalSection( &freetype_cs );
5617 return font->potm->otmSize;
5621 needed = sizeof(*potm);
5623 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5624 family_nameW = strdupW(font->name);
5626 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5627 * sizeof(WCHAR);
5628 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5629 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5630 style_nameW, lensty/sizeof(WCHAR));
5632 /* These names should be read from the TT name table */
5634 /* length of otmpFamilyName */
5635 needed += lenfam;
5637 /* length of otmpFaceName */
5638 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5639 needed += lenfam; /* just the family name */
5640 } else {
5641 needed += lenfam + lensty; /* family + " " + style */
5644 /* length of otmpStyleName */
5645 needed += lensty;
5647 /* length of otmpFullName */
5648 needed += lenfam + lensty;
5651 x_scale = ft_face->size->metrics.x_scale;
5652 y_scale = ft_face->size->metrics.y_scale;
5654 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5655 if(!pOS2) {
5656 FIXME("Can't find OS/2 table - not TT font?\n");
5657 ret = 0;
5658 goto end;
5661 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5662 if(!pHori) {
5663 FIXME("Can't find HHEA table - not TT font?\n");
5664 ret = 0;
5665 goto end;
5668 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5670 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",
5671 pOS2->usWinAscent, pOS2->usWinDescent,
5672 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5673 ft_face->ascender, ft_face->descender, ft_face->height,
5674 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5675 ft_face->bbox.yMax, ft_face->bbox.yMin);
5677 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5678 font->potm->otmSize = needed;
5680 #define TM font->potm->otmTextMetrics
5682 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5683 ascent = pHori->Ascender;
5684 descent = -pHori->Descender;
5685 } else {
5686 ascent = pOS2->usWinAscent;
5687 descent = pOS2->usWinDescent;
5690 if(font->yMax) {
5691 TM.tmAscent = font->yMax;
5692 TM.tmDescent = -font->yMin;
5693 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5694 } else {
5695 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5696 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5697 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5698 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5701 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5703 /* MSDN says:
5704 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5706 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5707 ((ascent + descent) -
5708 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5710 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5711 if (TM.tmAveCharWidth == 0) {
5712 TM.tmAveCharWidth = 1;
5714 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5715 TM.tmWeight = FW_REGULAR;
5716 if (font->fake_bold)
5717 TM.tmWeight = FW_BOLD;
5718 else
5720 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5722 if (pOS2->usWeightClass > FW_MEDIUM)
5723 TM.tmWeight = pOS2->usWeightClass;
5725 else if (pOS2->usWeightClass <= FW_MEDIUM)
5726 TM.tmWeight = pOS2->usWeightClass;
5728 TM.tmOverhang = 0;
5729 TM.tmDigitizedAspectX = 300;
5730 TM.tmDigitizedAspectY = 300;
5731 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5732 * symbol range to 0 - f0ff
5735 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5737 TM.tmFirstChar = 0;
5738 switch(GetACP())
5740 case 1257: /* Baltic */
5741 TM.tmLastChar = 0xf8fd;
5742 break;
5743 default:
5744 TM.tmLastChar = 0xf0ff;
5746 TM.tmBreakChar = 0x20;
5747 TM.tmDefaultChar = 0x1f;
5749 else
5751 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5752 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5754 if(pOS2->usFirstCharIndex <= 1)
5755 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5756 else if (pOS2->usFirstCharIndex > 0xff)
5757 TM.tmBreakChar = 0x20;
5758 else
5759 TM.tmBreakChar = pOS2->usFirstCharIndex;
5760 TM.tmDefaultChar = TM.tmBreakChar - 1;
5762 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5763 TM.tmUnderlined = font->underline;
5764 TM.tmStruckOut = font->strikeout;
5766 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5767 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5768 (pOS2->version == 0xFFFFU ||
5769 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5770 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5771 else
5772 TM.tmPitchAndFamily = 0;
5774 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5776 case PAN_FAMILY_SCRIPT:
5777 TM.tmPitchAndFamily |= FF_SCRIPT;
5778 break;
5780 case PAN_FAMILY_DECORATIVE:
5781 TM.tmPitchAndFamily |= FF_DECORATIVE;
5782 break;
5784 case PAN_ANY:
5785 case PAN_NO_FIT:
5786 case PAN_FAMILY_TEXT_DISPLAY:
5787 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5788 /* which is clearly not what the panose spec says. */
5789 default:
5790 if(TM.tmPitchAndFamily == 0 || /* fixed */
5791 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5792 TM.tmPitchAndFamily = FF_MODERN;
5793 else
5795 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5797 case PAN_ANY:
5798 case PAN_NO_FIT:
5799 default:
5800 TM.tmPitchAndFamily |= FF_DONTCARE;
5801 break;
5803 case PAN_SERIF_COVE:
5804 case PAN_SERIF_OBTUSE_COVE:
5805 case PAN_SERIF_SQUARE_COVE:
5806 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5807 case PAN_SERIF_SQUARE:
5808 case PAN_SERIF_THIN:
5809 case PAN_SERIF_BONE:
5810 case PAN_SERIF_EXAGGERATED:
5811 case PAN_SERIF_TRIANGLE:
5812 TM.tmPitchAndFamily |= FF_ROMAN;
5813 break;
5815 case PAN_SERIF_NORMAL_SANS:
5816 case PAN_SERIF_OBTUSE_SANS:
5817 case PAN_SERIF_PERP_SANS:
5818 case PAN_SERIF_FLARED:
5819 case PAN_SERIF_ROUNDED:
5820 TM.tmPitchAndFamily |= FF_SWISS;
5821 break;
5824 break;
5827 if(FT_IS_SCALABLE(ft_face))
5828 TM.tmPitchAndFamily |= TMPF_VECTOR;
5830 if(FT_IS_SFNT(ft_face))
5832 if (font->ntmFlags & NTM_PS_OPENTYPE)
5833 TM.tmPitchAndFamily |= TMPF_DEVICE;
5834 else
5835 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5838 TM.tmCharSet = font->charset;
5840 font->potm->otmFiller = 0;
5841 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5842 font->potm->otmfsSelection = pOS2->fsSelection;
5843 font->potm->otmfsType = pOS2->fsType;
5844 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5845 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5846 font->potm->otmItalicAngle = 0; /* POST table */
5847 font->potm->otmEMSquare = ft_face->units_per_EM;
5848 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5849 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5850 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5851 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5852 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5853 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5854 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5855 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5856 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5857 font->potm->otmMacAscent = TM.tmAscent;
5858 font->potm->otmMacDescent = -TM.tmDescent;
5859 font->potm->otmMacLineGap = font->potm->otmLineGap;
5860 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5861 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5862 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5863 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5864 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5865 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5866 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5867 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5868 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5869 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5870 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5871 if(!pPost) {
5872 font->potm->otmsUnderscoreSize = 0;
5873 font->potm->otmsUnderscorePosition = 0;
5874 } else {
5875 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5876 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5878 #undef TM
5880 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5881 cp = (char*)font->potm + sizeof(*font->potm);
5882 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5883 strcpyW((WCHAR*)cp, family_nameW);
5884 cp += lenfam;
5885 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5886 strcpyW((WCHAR*)cp, style_nameW);
5887 cp += lensty;
5888 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5889 strcpyW((WCHAR*)cp, family_nameW);
5890 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5891 strcatW((WCHAR*)cp, spaceW);
5892 strcatW((WCHAR*)cp, style_nameW);
5893 cp += lenfam + lensty;
5894 } else
5895 cp += lenfam;
5896 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5897 strcpyW((WCHAR*)cp, family_nameW);
5898 strcatW((WCHAR*)cp, spaceW);
5899 strcatW((WCHAR*)cp, style_nameW);
5900 ret = needed;
5902 if(potm && needed <= cbSize)
5904 memcpy(potm, font->potm, font->potm->otmSize);
5905 scale_outline_font_metrics(font, potm);
5908 end:
5909 HeapFree(GetProcessHeap(), 0, style_nameW);
5910 HeapFree(GetProcessHeap(), 0, family_nameW);
5912 LeaveCriticalSection( &freetype_cs );
5913 return ret;
5916 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5918 HFONTLIST *hfontlist;
5919 child->font = alloc_font();
5920 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5921 if(!child->font->ft_face)
5923 free_font(child->font);
5924 child->font = NULL;
5925 return FALSE;
5928 child->font->font_desc = font->font_desc;
5929 child->font->ntmFlags = child->face->ntmFlags;
5930 child->font->orientation = font->orientation;
5931 child->font->scale_y = font->scale_y;
5932 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5933 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5934 child->font->name = strdupW(child->face->family->FamilyName);
5935 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5936 child->font->base_font = font;
5937 list_add_head(&child_font_list, &child->font->entry);
5938 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5939 return TRUE;
5942 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5944 FT_UInt g;
5945 CHILD_FONT *child_font;
5947 if(font->base_font)
5948 font = font->base_font;
5950 *linked_font = font;
5952 if((*glyph = get_glyph_index(font, c)))
5953 return TRUE;
5955 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5957 if(!child_font->font)
5958 if(!load_child_font(font, child_font))
5959 continue;
5961 if(!child_font->font->ft_face)
5962 continue;
5963 g = get_glyph_index(child_font->font, c);
5964 if(g)
5966 *glyph = g;
5967 *linked_font = child_font->font;
5968 return TRUE;
5971 return FALSE;
5974 /*************************************************************
5975 * WineEngGetCharWidth
5978 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5979 LPINT buffer)
5981 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5982 UINT c;
5983 GLYPHMETRICS gm;
5984 FT_UInt glyph_index;
5985 GdiFont *linked_font;
5987 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5989 GDI_CheckNotLock();
5990 EnterCriticalSection( &freetype_cs );
5991 for(c = firstChar; c <= lastChar; c++) {
5992 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5993 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5994 &gm, 0, NULL, &identity);
5995 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5997 LeaveCriticalSection( &freetype_cs );
5998 return TRUE;
6001 /*************************************************************
6002 * WineEngGetCharABCWidths
6005 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6006 LPABC buffer)
6008 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6009 UINT c;
6010 GLYPHMETRICS gm;
6011 FT_UInt glyph_index;
6012 GdiFont *linked_font;
6014 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6016 if(!FT_IS_SCALABLE(font->ft_face))
6017 return FALSE;
6019 GDI_CheckNotLock();
6020 EnterCriticalSection( &freetype_cs );
6022 for(c = firstChar; c <= lastChar; c++) {
6023 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6024 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6025 &gm, 0, NULL, &identity);
6026 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6027 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6028 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6029 FONT_GM(linked_font,glyph_index)->bbx;
6031 LeaveCriticalSection( &freetype_cs );
6032 return TRUE;
6035 /*************************************************************
6036 * WineEngGetCharABCWidthsFloat
6039 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6041 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6042 UINT c;
6043 GLYPHMETRICS gm;
6044 FT_UInt glyph_index;
6045 GdiFont *linked_font;
6047 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6049 GDI_CheckNotLock();
6050 EnterCriticalSection( &freetype_cs );
6052 for (c = first; c <= last; c++)
6054 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6055 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6056 &gm, 0, NULL, &identity);
6057 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6058 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6059 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6060 FONT_GM(linked_font, glyph_index)->lsb -
6061 FONT_GM(linked_font, glyph_index)->bbx;
6063 LeaveCriticalSection( &freetype_cs );
6064 return TRUE;
6067 /*************************************************************
6068 * WineEngGetCharABCWidthsI
6071 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6072 LPABC buffer)
6074 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6075 UINT c;
6076 GLYPHMETRICS gm;
6077 FT_UInt glyph_index;
6078 GdiFont *linked_font;
6080 if(!FT_HAS_HORIZONTAL(font->ft_face))
6081 return FALSE;
6083 GDI_CheckNotLock();
6084 EnterCriticalSection( &freetype_cs );
6086 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6087 if (!pgi)
6088 for(c = firstChar; c < firstChar+count; c++) {
6089 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6090 &gm, 0, NULL, &identity);
6091 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6092 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6093 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6094 - FONT_GM(linked_font,c)->bbx;
6096 else
6097 for(c = 0; c < count; c++) {
6098 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6099 &gm, 0, NULL, &identity);
6100 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6101 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6102 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6103 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6106 LeaveCriticalSection( &freetype_cs );
6107 return TRUE;
6110 /*************************************************************
6111 * WineEngGetTextExtentExPoint
6114 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6115 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6117 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6118 INT idx;
6119 INT nfit = 0, ext;
6120 GLYPHMETRICS gm;
6121 TEXTMETRICW tm;
6122 FT_UInt glyph_index;
6123 GdiFont *linked_font;
6125 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6126 max_ext, size);
6128 GDI_CheckNotLock();
6129 EnterCriticalSection( &freetype_cs );
6131 size->cx = 0;
6132 WineEngGetTextMetrics(font, &tm);
6133 size->cy = tm.tmHeight;
6135 for(idx = 0; idx < count; idx++) {
6136 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6137 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6138 &gm, 0, NULL, &identity);
6139 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6140 ext = size->cx;
6141 if (! pnfit || ext <= max_ext) {
6142 ++nfit;
6143 if (dxs)
6144 dxs[idx] = ext;
6148 if (pnfit)
6149 *pnfit = nfit;
6151 LeaveCriticalSection( &freetype_cs );
6152 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6153 return TRUE;
6156 /*************************************************************
6157 * WineEngGetTextExtentExPointI
6160 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6161 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6163 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6164 INT idx;
6165 INT nfit = 0, ext;
6166 GLYPHMETRICS gm;
6167 TEXTMETRICW tm;
6169 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6171 GDI_CheckNotLock();
6172 EnterCriticalSection( &freetype_cs );
6174 size->cx = 0;
6175 WineEngGetTextMetrics(font, &tm);
6176 size->cy = tm.tmHeight;
6178 for(idx = 0; idx < count; idx++) {
6179 WineEngGetGlyphOutline(font, indices[idx],
6180 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6181 &identity);
6182 size->cx += FONT_GM(font,indices[idx])->adv;
6183 ext = size->cx;
6184 if (! pnfit || ext <= max_ext) {
6185 ++nfit;
6186 if (dxs)
6187 dxs[idx] = ext;
6191 if (pnfit)
6192 *pnfit = nfit;
6194 LeaveCriticalSection( &freetype_cs );
6195 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6196 return TRUE;
6199 /*************************************************************
6200 * WineEngGetFontData
6203 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6204 DWORD cbData)
6206 FT_Face ft_face = font->ft_face;
6207 FT_ULong len;
6208 FT_Error err;
6210 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6211 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6212 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6214 if(!FT_IS_SFNT(ft_face))
6215 return GDI_ERROR;
6217 if(!buf)
6218 len = 0;
6219 else
6220 len = cbData;
6222 if(table) { /* MS tags differ in endianness from FT ones */
6223 table = table >> 24 | table << 24 |
6224 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6227 /* make sure value of len is the value freetype says it needs */
6228 if(buf && len)
6230 FT_ULong needed = 0;
6231 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6232 if( !err && needed < len) len = needed;
6234 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6236 if(err) {
6237 TRACE("Can't find table %c%c%c%c\n",
6238 /* bytes were reversed */
6239 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6240 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6241 return GDI_ERROR;
6243 return len;
6246 /*************************************************************
6247 * WineEngGetTextFace
6250 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6252 INT n = strlenW(font->name) + 1;
6253 if(str) {
6254 lstrcpynW(str, font->name, count);
6255 return min(count, n);
6256 } else
6257 return n;
6260 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6262 if (fs) *fs = font->fs;
6263 return font->charset;
6266 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6268 GdiFont *font = dc->gdiFont, *linked_font;
6269 struct list *first_hfont;
6270 BOOL ret;
6272 GDI_CheckNotLock();
6273 EnterCriticalSection( &freetype_cs );
6274 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6275 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6276 if(font == linked_font)
6277 *new_hfont = dc->hFont;
6278 else
6280 first_hfont = list_head(&linked_font->hfontlist);
6281 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6283 LeaveCriticalSection( &freetype_cs );
6284 return ret;
6287 /* Retrieve a list of supported Unicode ranges for a given font.
6288 * Can be called with NULL gs to calculate the buffer size. Returns
6289 * the number of ranges found.
6291 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6293 DWORD num_ranges = 0;
6295 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6297 FT_UInt glyph_code;
6298 FT_ULong char_code, char_code_prev;
6300 glyph_code = 0;
6301 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6303 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6304 face->num_glyphs, glyph_code, char_code);
6306 if (!glyph_code) return 0;
6308 if (gs)
6310 gs->ranges[0].wcLow = (USHORT)char_code;
6311 gs->ranges[0].cGlyphs = 0;
6312 gs->cGlyphsSupported = 0;
6315 num_ranges = 1;
6316 while (glyph_code)
6318 if (char_code < char_code_prev)
6320 ERR("expected increasing char code from FT_Get_Next_Char\n");
6321 return 0;
6323 if (char_code - char_code_prev > 1)
6325 num_ranges++;
6326 if (gs)
6328 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6329 gs->ranges[num_ranges - 1].cGlyphs = 1;
6330 gs->cGlyphsSupported++;
6333 else if (gs)
6335 gs->ranges[num_ranges - 1].cGlyphs++;
6336 gs->cGlyphsSupported++;
6338 char_code_prev = char_code;
6339 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6342 else
6343 FIXME("encoding %u not supported\n", face->charmap->encoding);
6345 return num_ranges;
6348 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6350 DWORD size = 0;
6351 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6353 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6354 if (glyphset)
6356 glyphset->cbThis = size;
6357 glyphset->cRanges = num_ranges;
6358 glyphset->flAccel = 0;
6360 return size;
6363 /*************************************************************
6364 * FontIsLinked
6366 BOOL WineEngFontIsLinked(GdiFont *font)
6368 BOOL ret;
6369 GDI_CheckNotLock();
6370 EnterCriticalSection( &freetype_cs );
6371 ret = !list_empty(&font->child_fonts);
6372 LeaveCriticalSection( &freetype_cs );
6373 return ret;
6376 static BOOL is_hinting_enabled(void)
6378 /* Use the >= 2.2.0 function if available */
6379 if(pFT_Get_TrueType_Engine_Type)
6381 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6382 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6384 #ifdef FT_DRIVER_HAS_HINTER
6385 else
6387 FT_Module mod;
6389 /* otherwise if we've been compiled with < 2.2.0 headers
6390 use the internal macro */
6391 mod = pFT_Get_Module(library, "truetype");
6392 if(mod && FT_DRIVER_HAS_HINTER(mod))
6393 return TRUE;
6395 #endif
6397 return FALSE;
6400 static BOOL is_subpixel_rendering_enabled( void )
6402 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6403 return pFT_Library_SetLcdFilter &&
6404 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6405 #else
6406 return FALSE;
6407 #endif
6410 /*************************************************************************
6411 * GetRasterizerCaps (GDI32.@)
6413 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6415 static int hinting = -1;
6416 static int subpixel = -1;
6418 if(hinting == -1)
6420 hinting = is_hinting_enabled();
6421 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6424 if ( subpixel == -1 )
6426 subpixel = is_subpixel_rendering_enabled();
6427 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6430 lprs->nSize = sizeof(RASTERIZER_STATUS);
6431 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6432 if ( subpixel )
6433 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6434 lprs->nLanguageID = 0;
6435 return TRUE;
6438 /*************************************************************
6439 * WineEngRealizationInfo
6441 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6443 FIXME("(%p, %p): stub!\n", font, info);
6445 info->flags = 1;
6446 if(FT_IS_SCALABLE(font->ft_face))
6447 info->flags |= 2;
6449 info->cache_num = font->cache_num;
6450 info->unknown2 = -1;
6451 return TRUE;
6454 /*************************************************************************
6455 * Kerning support for TrueType fonts
6457 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6459 struct TT_kern_table
6461 USHORT version;
6462 USHORT nTables;
6465 struct TT_kern_subtable
6467 USHORT version;
6468 USHORT length;
6469 union
6471 USHORT word;
6472 struct
6474 USHORT horizontal : 1;
6475 USHORT minimum : 1;
6476 USHORT cross_stream: 1;
6477 USHORT override : 1;
6478 USHORT reserved1 : 4;
6479 USHORT format : 8;
6480 } bits;
6481 } coverage;
6484 struct TT_format0_kern_subtable
6486 USHORT nPairs;
6487 USHORT searchRange;
6488 USHORT entrySelector;
6489 USHORT rangeShift;
6492 struct TT_kern_pair
6494 USHORT left;
6495 USHORT right;
6496 short value;
6499 static DWORD parse_format0_kern_subtable(GdiFont *font,
6500 const struct TT_format0_kern_subtable *tt_f0_ks,
6501 const USHORT *glyph_to_char,
6502 KERNINGPAIR *kern_pair, DWORD cPairs)
6504 USHORT i, nPairs;
6505 const struct TT_kern_pair *tt_kern_pair;
6507 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6509 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6511 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6512 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6513 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6515 if (!kern_pair || !cPairs)
6516 return nPairs;
6518 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6520 nPairs = min(nPairs, cPairs);
6522 for (i = 0; i < nPairs; i++)
6524 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6525 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6526 /* this algorithm appears to better match what Windows does */
6527 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6528 if (kern_pair->iKernAmount < 0)
6530 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6531 kern_pair->iKernAmount -= font->ppem;
6533 else if (kern_pair->iKernAmount > 0)
6535 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6536 kern_pair->iKernAmount += font->ppem;
6538 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6540 TRACE("left %u right %u value %d\n",
6541 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6543 kern_pair++;
6545 TRACE("copied %u entries\n", nPairs);
6546 return nPairs;
6549 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6551 DWORD length;
6552 void *buf;
6553 const struct TT_kern_table *tt_kern_table;
6554 const struct TT_kern_subtable *tt_kern_subtable;
6555 USHORT i, nTables;
6556 USHORT *glyph_to_char;
6558 GDI_CheckNotLock();
6559 EnterCriticalSection( &freetype_cs );
6560 if (font->total_kern_pairs != (DWORD)-1)
6562 if (cPairs && kern_pair)
6564 cPairs = min(cPairs, font->total_kern_pairs);
6565 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6566 LeaveCriticalSection( &freetype_cs );
6567 return cPairs;
6569 LeaveCriticalSection( &freetype_cs );
6570 return font->total_kern_pairs;
6573 font->total_kern_pairs = 0;
6575 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6577 if (length == GDI_ERROR)
6579 TRACE("no kerning data in the font\n");
6580 LeaveCriticalSection( &freetype_cs );
6581 return 0;
6584 buf = HeapAlloc(GetProcessHeap(), 0, length);
6585 if (!buf)
6587 WARN("Out of memory\n");
6588 LeaveCriticalSection( &freetype_cs );
6589 return 0;
6592 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6594 /* build a glyph index to char code map */
6595 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6596 if (!glyph_to_char)
6598 WARN("Out of memory allocating a glyph index to char code map\n");
6599 HeapFree(GetProcessHeap(), 0, buf);
6600 LeaveCriticalSection( &freetype_cs );
6601 return 0;
6604 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6606 FT_UInt glyph_code;
6607 FT_ULong char_code;
6609 glyph_code = 0;
6610 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6612 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6613 font->ft_face->num_glyphs, glyph_code, char_code);
6615 while (glyph_code)
6617 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6619 /* FIXME: This doesn't match what Windows does: it does some fancy
6620 * things with duplicate glyph index to char code mappings, while
6621 * we just avoid overriding existing entries.
6623 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6624 glyph_to_char[glyph_code] = (USHORT)char_code;
6626 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6629 else
6631 ULONG n;
6633 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6634 for (n = 0; n <= 65535; n++)
6635 glyph_to_char[n] = (USHORT)n;
6638 tt_kern_table = buf;
6639 nTables = GET_BE_WORD(tt_kern_table->nTables);
6640 TRACE("version %u, nTables %u\n",
6641 GET_BE_WORD(tt_kern_table->version), nTables);
6643 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6645 for (i = 0; i < nTables; i++)
6647 struct TT_kern_subtable tt_kern_subtable_copy;
6649 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6650 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6651 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6653 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6654 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6655 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6657 /* According to the TrueType specification this is the only format
6658 * that will be properly interpreted by Windows and OS/2
6660 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6662 DWORD new_chunk, old_total = font->total_kern_pairs;
6664 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6665 glyph_to_char, NULL, 0);
6666 font->total_kern_pairs += new_chunk;
6668 if (!font->kern_pairs)
6669 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6670 font->total_kern_pairs * sizeof(*font->kern_pairs));
6671 else
6672 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6673 font->total_kern_pairs * sizeof(*font->kern_pairs));
6675 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6676 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6678 else
6679 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6681 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6684 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6685 HeapFree(GetProcessHeap(), 0, buf);
6687 if (cPairs && kern_pair)
6689 cPairs = min(cPairs, font->total_kern_pairs);
6690 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6691 LeaveCriticalSection( &freetype_cs );
6692 return cPairs;
6694 LeaveCriticalSection( &freetype_cs );
6695 return font->total_kern_pairs;
6698 #else /* HAVE_FREETYPE */
6700 /*************************************************************************/
6702 BOOL WineEngInit(void)
6704 return FALSE;
6706 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6708 return NULL;
6710 BOOL WineEngDestroyFontInstance(HFONT hfont)
6712 return FALSE;
6715 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6717 return 1;
6720 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6721 LPWORD pgi, DWORD flags)
6723 return GDI_ERROR;
6726 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6727 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6728 const MAT2* lpmat)
6730 ERR("called but we don't have FreeType\n");
6731 return GDI_ERROR;
6734 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6736 ERR("called but we don't have FreeType\n");
6737 return FALSE;
6740 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6741 OUTLINETEXTMETRICW *potm)
6743 ERR("called but we don't have FreeType\n");
6744 return 0;
6747 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6748 LPINT buffer)
6750 ERR("called but we don't have FreeType\n");
6751 return FALSE;
6754 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6755 LPABC buffer)
6757 ERR("called but we don't have FreeType\n");
6758 return FALSE;
6761 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6763 ERR("called but we don't have FreeType\n");
6764 return FALSE;
6767 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6768 LPABC buffer)
6770 ERR("called but we don't have FreeType\n");
6771 return FALSE;
6774 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6775 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6777 ERR("called but we don't have FreeType\n");
6778 return FALSE;
6781 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6782 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6784 ERR("called but we don't have FreeType\n");
6785 return FALSE;
6788 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6789 DWORD cbData)
6791 ERR("called but we don't have FreeType\n");
6792 return GDI_ERROR;
6795 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6797 ERR("called but we don't have FreeType\n");
6798 return 0;
6801 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6803 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6804 return 1;
6807 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6809 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6810 return TRUE;
6813 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6815 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6816 return NULL;
6819 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6821 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6822 return DEFAULT_CHARSET;
6825 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6827 return FALSE;
6830 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6832 FIXME("(%p, %p): stub\n", font, glyphset);
6833 return 0;
6836 BOOL WineEngFontIsLinked(GdiFont *font)
6838 return FALSE;
6841 /*************************************************************************
6842 * GetRasterizerCaps (GDI32.@)
6844 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6846 lprs->nSize = sizeof(RASTERIZER_STATUS);
6847 lprs->wFlags = 0;
6848 lprs->nLanguageID = 0;
6849 return TRUE;
6852 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6854 ERR("called but we don't have FreeType\n");
6855 return 0;
6858 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6860 ERR("called but we don't have FreeType\n");
6861 return FALSE;
6864 #endif /* HAVE_FREETYPE */