gdi32: Use a separate variable to indicate the default has been retrieved.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob81c704b911cf31a46976c07503703b7bc69c2262
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 struct list faces;
286 } Family;
288 typedef struct {
289 GLYPHMETRICS gm;
290 INT adv; /* These three hold to widths of the unrotated chars */
291 INT lsb;
292 INT bbx;
293 BOOL init;
294 } GM;
296 typedef struct {
297 FLOAT eM11, eM12;
298 FLOAT eM21, eM22;
299 } FMAT2;
301 typedef struct {
302 DWORD hash;
303 LOGFONTW lf;
304 FMAT2 matrix;
305 BOOL can_use_bitmap;
306 } FONT_DESC;
308 typedef struct tagHFONTLIST {
309 struct list entry;
310 HFONT hfont;
311 } HFONTLIST;
313 typedef struct {
314 struct list entry;
315 Face *face;
316 GdiFont *font;
317 } CHILD_FONT;
319 struct tagGdiFont {
320 struct list entry;
321 GM **gm;
322 DWORD gmsize;
323 struct list hfontlist;
324 OUTLINETEXTMETRICW *potm;
325 DWORD total_kern_pairs;
326 KERNINGPAIR *kern_pairs;
327 struct list child_fonts;
329 /* the following members can be accessed without locking, they are never modified after creation */
330 FT_Face ft_face;
331 struct font_mapping *mapping;
332 LPWSTR name;
333 int charset;
334 int codepage;
335 BOOL fake_italic;
336 BOOL fake_bold;
337 BYTE underline;
338 BYTE strikeout;
339 INT orientation;
340 FONT_DESC font_desc;
341 LONG aveWidth, ppem;
342 double scale_y;
343 SHORT yMax;
344 SHORT yMin;
345 DWORD ntmFlags;
346 FONTSIGNATURE fs;
347 GdiFont *base_font;
348 VOID *GSUB_Table;
349 DWORD cache_num;
352 typedef struct {
353 struct list entry;
354 const WCHAR *font_name;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 LPCWSTR name;
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
383 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
384 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
386 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
387 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
388 'W','i','n','d','o','w','s','\\',
389 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
390 'F','o','n','t','s','\0'};
392 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
393 'W','i','n','d','o','w','s',' ','N','T','\\',
394 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
395 'F','o','n','t','s','\0'};
397 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
398 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
399 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
400 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
402 static const WCHAR * const SystemFontValues[4] = {
403 System_Value,
404 OEMFont_Value,
405 FixedSys_Value,
406 NULL
409 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
410 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
412 /* Interesting and well-known (frequently-assumed!) font names */
413 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
414 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 };
415 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
416 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
417 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
418 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
419 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
420 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
422 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
423 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
424 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
425 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
426 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
427 'E','u','r','o','p','e','a','n','\0'};
428 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
429 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
430 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
431 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
432 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
433 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
434 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
435 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
436 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
437 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
438 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
439 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
441 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
442 WesternW, /*00*/
443 Central_EuropeanW,
444 CyrillicW,
445 GreekW,
446 TurkishW,
447 HebrewW,
448 ArabicW,
449 BalticW,
450 VietnameseW, /*08*/
451 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
452 ThaiW,
453 JapaneseW,
454 CHINESE_GB2312W,
455 HangulW,
456 CHINESE_BIG5W,
457 Hangul_Johab_W,
458 NULL, NULL, /*23*/
459 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
460 SymbolW /*31*/
463 typedef struct {
464 WCHAR *name;
465 INT charset;
466 } NameCs;
468 typedef struct tagFontSubst {
469 struct list entry;
470 NameCs from;
471 NameCs to;
472 } FontSubst;
474 struct font_mapping
476 struct list entry;
477 int refcount;
478 dev_t dev;
479 ino_t ino;
480 void *data;
481 size_t size;
484 static struct list mappings_list = LIST_INIT( mappings_list );
486 static CRITICAL_SECTION freetype_cs;
487 static CRITICAL_SECTION_DEBUG critsect_debug =
489 0, 0, &freetype_cs,
490 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
491 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
493 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
495 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
497 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
498 static BOOL use_default_fallback = FALSE;
500 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
502 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
503 'W','i','n','d','o','w','s',' ','N','T','\\',
504 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
505 'S','y','s','t','e','m','L','i','n','k',0};
507 /****************************************
508 * Notes on .fon files
510 * The fonts System, FixedSys and Terminal are special. There are typically multiple
511 * versions installed for different resolutions and codepages. Windows stores which one to use
512 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
513 * Key Meaning
514 * FIXEDFON.FON FixedSys
515 * FONTS.FON System
516 * OEMFONT.FON Terminal
517 * LogPixels Current dpi set by the display control panel applet
518 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
519 * also has a LogPixels value that appears to mirror this)
521 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
522 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
523 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
524 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
525 * so that makes sense.
527 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
528 * to be mapped into the registry on Windows 2000 at least).
529 * I have
530 * woafont=app850.fon
531 * ega80woa.fon=ega80850.fon
532 * ega40woa.fon=ega40850.fon
533 * cga80woa.fon=cga80850.fon
534 * cga40woa.fon=cga40850.fon
537 /* These are all structures needed for the GSUB table */
539 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
540 #define TATEGAKI_LOWER_BOUND 0x02F1
542 typedef struct {
543 DWORD version;
544 WORD ScriptList;
545 WORD FeatureList;
546 WORD LookupList;
547 } GSUB_Header;
549 typedef struct {
550 CHAR ScriptTag[4];
551 WORD Script;
552 } GSUB_ScriptRecord;
554 typedef struct {
555 WORD ScriptCount;
556 GSUB_ScriptRecord ScriptRecord[1];
557 } GSUB_ScriptList;
559 typedef struct {
560 CHAR LangSysTag[4];
561 WORD LangSys;
562 } GSUB_LangSysRecord;
564 typedef struct {
565 WORD DefaultLangSys;
566 WORD LangSysCount;
567 GSUB_LangSysRecord LangSysRecord[1];
568 } GSUB_Script;
570 typedef struct {
571 WORD LookupOrder; /* Reserved */
572 WORD ReqFeatureIndex;
573 WORD FeatureCount;
574 WORD FeatureIndex[1];
575 } GSUB_LangSys;
577 typedef struct {
578 CHAR FeatureTag[4];
579 WORD Feature;
580 } GSUB_FeatureRecord;
582 typedef struct {
583 WORD FeatureCount;
584 GSUB_FeatureRecord FeatureRecord[1];
585 } GSUB_FeatureList;
587 typedef struct {
588 WORD FeatureParams; /* Reserved */
589 WORD LookupCount;
590 WORD LookupListIndex[1];
591 } GSUB_Feature;
593 typedef struct {
594 WORD LookupCount;
595 WORD Lookup[1];
596 } GSUB_LookupList;
598 typedef struct {
599 WORD LookupType;
600 WORD LookupFlag;
601 WORD SubTableCount;
602 WORD SubTable[1];
603 } GSUB_LookupTable;
605 typedef struct {
606 WORD CoverageFormat;
607 WORD GlyphCount;
608 WORD GlyphArray[1];
609 } GSUB_CoverageFormat1;
611 typedef struct {
612 WORD Start;
613 WORD End;
614 WORD StartCoverageIndex;
615 } GSUB_RangeRecord;
617 typedef struct {
618 WORD CoverageFormat;
619 WORD RangeCount;
620 GSUB_RangeRecord RangeRecord[1];
621 } GSUB_CoverageFormat2;
623 typedef struct {
624 WORD SubstFormat; /* = 1 */
625 WORD Coverage;
626 WORD DeltaGlyphID;
627 } GSUB_SingleSubstFormat1;
629 typedef struct {
630 WORD SubstFormat; /* = 2 */
631 WORD Coverage;
632 WORD GlyphCount;
633 WORD Substitute[1];
634 }GSUB_SingleSubstFormat2;
636 #ifdef HAVE_CARBON_CARBON_H
637 static char *find_cache_dir(void)
639 FSRef ref;
640 OSErr err;
641 static char cached_path[MAX_PATH];
642 static const char *wine = "/Wine", *fonts = "/Fonts";
644 if(*cached_path) return cached_path;
646 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
647 if(err != noErr)
649 WARN("can't create cached data folder\n");
650 return NULL;
652 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
653 if(err != noErr)
655 WARN("can't create cached data path\n");
656 *cached_path = '\0';
657 return NULL;
659 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
661 ERR("Could not create full path\n");
662 *cached_path = '\0';
663 return NULL;
665 strcat(cached_path, wine);
667 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
669 WARN("Couldn't mkdir %s\n", cached_path);
670 *cached_path = '\0';
671 return NULL;
673 strcat(cached_path, fonts);
674 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
676 WARN("Couldn't mkdir %s\n", cached_path);
677 *cached_path = '\0';
678 return NULL;
680 return cached_path;
683 /******************************************************************
684 * expand_mac_font
686 * Extracts individual TrueType font files from a Mac suitcase font
687 * and saves them into the user's caches directory (see
688 * find_cache_dir()).
689 * Returns a NULL terminated array of filenames.
691 * We do this because they are apps that try to read ttf files
692 * themselves and they don't like Mac suitcase files.
694 static char **expand_mac_font(const char *path)
696 FSRef ref;
697 SInt16 res_ref;
698 OSStatus s;
699 unsigned int idx;
700 const char *out_dir;
701 const char *filename;
702 int output_len;
703 struct {
704 char **array;
705 unsigned int size, max_size;
706 } ret;
708 TRACE("path %s\n", path);
710 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
711 if(s != noErr)
713 WARN("failed to get ref\n");
714 return NULL;
717 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
718 if(s != noErr)
720 TRACE("no data fork, so trying resource fork\n");
721 res_ref = FSOpenResFile(&ref, fsRdPerm);
722 if(res_ref == -1)
724 TRACE("unable to open resource fork\n");
725 return NULL;
729 ret.size = 0;
730 ret.max_size = 10;
731 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
732 if(!ret.array)
734 CloseResFile(res_ref);
735 return NULL;
738 out_dir = find_cache_dir();
740 filename = strrchr(path, '/');
741 if(!filename) filename = path;
742 else filename++;
744 /* output filename has the form out_dir/filename_%04x.ttf */
745 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
747 UseResFile(res_ref);
748 idx = 1;
749 while(1)
751 FamRec *fam_rec;
752 unsigned short *num_faces_ptr, num_faces, face;
753 AsscEntry *assoc;
754 Handle fond;
755 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
757 fond = Get1IndResource(fond_res, idx);
758 if(!fond) break;
759 TRACE("got fond resource %d\n", idx);
760 HLock(fond);
762 fam_rec = *(FamRec**)fond;
763 num_faces_ptr = (unsigned short *)(fam_rec + 1);
764 num_faces = GET_BE_WORD(*num_faces_ptr);
765 num_faces++;
766 assoc = (AsscEntry*)(num_faces_ptr + 1);
767 TRACE("num faces %04x\n", num_faces);
768 for(face = 0; face < num_faces; face++, assoc++)
770 Handle sfnt;
771 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
772 unsigned short size, font_id;
773 char *output;
775 size = GET_BE_WORD(assoc->fontSize);
776 font_id = GET_BE_WORD(assoc->fontID);
777 if(size != 0)
779 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
780 continue;
783 TRACE("trying to load sfnt id %04x\n", font_id);
784 sfnt = GetResource(sfnt_res, font_id);
785 if(!sfnt)
787 TRACE("can't get sfnt resource %04x\n", font_id);
788 continue;
791 output = HeapAlloc(GetProcessHeap(), 0, output_len);
792 if(output)
794 int fd;
796 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
798 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
799 if(fd != -1 || errno == EEXIST)
801 if(fd != -1)
803 unsigned char *sfnt_data;
805 HLock(sfnt);
806 sfnt_data = *(unsigned char**)sfnt;
807 write(fd, sfnt_data, GetHandleSize(sfnt));
808 HUnlock(sfnt);
809 close(fd);
811 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
813 ret.max_size *= 2;
814 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
816 ret.array[ret.size++] = output;
818 else
820 WARN("unable to create %s\n", output);
821 HeapFree(GetProcessHeap(), 0, output);
824 ReleaseResource(sfnt);
826 HUnlock(fond);
827 ReleaseResource(fond);
828 idx++;
830 CloseResFile(res_ref);
832 return ret.array;
835 #endif /* HAVE_CARBON_CARBON_H */
837 static inline BOOL is_win9x(void)
839 return GetVersion() & 0x80000000;
842 This function builds an FT_Fixed from a double. It fails if the absolute
843 value of the float number is greater than 32768.
845 static inline FT_Fixed FT_FixedFromFloat(double f)
847 return f * 0x10000;
851 This function builds an FT_Fixed from a FIXED. It simply put f.value
852 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
854 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
856 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
860 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
862 Family *family;
863 Face *face;
864 const char *file;
865 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
866 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
868 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
869 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
871 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
873 if(face_name && strcmpiW(face_name, family->FamilyName))
874 continue;
875 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
877 if (!face->file)
878 continue;
879 file = strrchr(face->file, '/');
880 if(!file)
881 file = face->file;
882 else
883 file++;
884 if(!strcasecmp(file, file_nameA))
886 HeapFree(GetProcessHeap(), 0, file_nameA);
887 return face;
891 HeapFree(GetProcessHeap(), 0, file_nameA);
892 return NULL;
895 static Family *find_family_from_name(const WCHAR *name)
897 Family *family;
899 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
901 if(!strcmpiW(family->FamilyName, name))
902 return family;
905 return NULL;
908 static void DumpSubstList(void)
910 FontSubst *psub;
912 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
914 if(psub->from.charset != -1 || psub->to.charset != -1)
915 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
916 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
917 else
918 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
919 debugstr_w(psub->to.name));
921 return;
924 static LPWSTR strdupW(LPCWSTR p)
926 LPWSTR ret;
927 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
928 ret = HeapAlloc(GetProcessHeap(), 0, len);
929 memcpy(ret, p, len);
930 return ret;
933 static LPSTR strdupA(LPCSTR p)
935 LPSTR ret;
936 DWORD len = (strlen(p) + 1);
937 ret = HeapAlloc(GetProcessHeap(), 0, len);
938 memcpy(ret, p, len);
939 return ret;
942 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
943 INT from_charset)
945 FontSubst *element;
947 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
949 if(!strcmpiW(element->from.name, from_name) &&
950 (element->from.charset == from_charset ||
951 element->from.charset == -1))
952 return element;
955 return NULL;
958 #define ADD_FONT_SUBST_FORCE 1
960 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
962 FontSubst *from_exist, *to_exist;
964 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
966 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
968 list_remove(&from_exist->entry);
969 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
970 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
971 HeapFree(GetProcessHeap(), 0, from_exist);
972 from_exist = NULL;
975 if(!from_exist)
977 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
979 if(to_exist)
981 HeapFree(GetProcessHeap(), 0, subst->to.name);
982 subst->to.name = strdupW(to_exist->to.name);
985 list_add_tail(subst_list, &subst->entry);
987 return TRUE;
990 HeapFree(GetProcessHeap(), 0, subst->from.name);
991 HeapFree(GetProcessHeap(), 0, subst->to.name);
992 HeapFree(GetProcessHeap(), 0, subst);
993 return FALSE;
996 static void split_subst_info(NameCs *nc, LPSTR str)
998 CHAR *p = strrchr(str, ',');
999 DWORD len;
1001 nc->charset = -1;
1002 if(p && *(p+1)) {
1003 nc->charset = strtol(p+1, NULL, 10);
1004 *p = '\0';
1006 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1007 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1008 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1011 static void LoadSubstList(void)
1013 FontSubst *psub;
1014 HKEY hkey;
1015 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1016 LPSTR value;
1017 LPVOID data;
1019 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1020 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1021 &hkey) == ERROR_SUCCESS) {
1023 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1024 &valuelen, &datalen, NULL, NULL);
1026 valuelen++; /* returned value doesn't include room for '\0' */
1027 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1028 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1030 dlen = datalen;
1031 vlen = valuelen;
1032 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1033 &dlen) == ERROR_SUCCESS) {
1034 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1036 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1037 split_subst_info(&psub->from, value);
1038 split_subst_info(&psub->to, data);
1040 /* Win 2000 doesn't allow mapping between different charsets
1041 or mapping of DEFAULT_CHARSET */
1042 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1043 psub->to.charset == DEFAULT_CHARSET) {
1044 HeapFree(GetProcessHeap(), 0, psub->to.name);
1045 HeapFree(GetProcessHeap(), 0, psub->from.name);
1046 HeapFree(GetProcessHeap(), 0, psub);
1047 } else {
1048 add_font_subst(&font_subst_list, psub, 0);
1050 /* reset dlen and vlen */
1051 dlen = datalen;
1052 vlen = valuelen;
1054 HeapFree(GetProcessHeap(), 0, data);
1055 HeapFree(GetProcessHeap(), 0, value);
1056 RegCloseKey(hkey);
1061 /*****************************************************************
1062 * get_name_table_entry
1064 * Supply the platform, encoding, language and name ids in req
1065 * and if the name exists the function will fill in the string
1066 * and string_len members. The string is owned by FreeType so
1067 * don't free it. Returns TRUE if the name is found else FALSE.
1069 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1071 FT_SfntName name;
1072 FT_UInt num_names, name_index;
1074 if(FT_IS_SFNT(ft_face))
1076 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1078 for(name_index = 0; name_index < num_names; name_index++)
1080 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1082 if((name.platform_id == req->platform_id) &&
1083 (name.encoding_id == req->encoding_id) &&
1084 (name.language_id == req->language_id) &&
1085 (name.name_id == req->name_id))
1087 req->string = name.string;
1088 req->string_len = name.string_len;
1089 return TRUE;
1094 req->string = NULL;
1095 req->string_len = 0;
1096 return FALSE;
1099 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1101 WCHAR *ret = NULL;
1102 FT_SfntName name;
1104 name.platform_id = TT_PLATFORM_MICROSOFT;
1105 name.encoding_id = TT_MS_ID_UNICODE_CS;
1106 name.language_id = language_id;
1107 name.name_id = name_id;
1109 if(get_name_table_entry(ft_face, &name))
1111 FT_UInt i;
1113 /* String is not nul terminated and string_len is a byte length. */
1114 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1115 for(i = 0; i < name.string_len / 2; i++)
1117 WORD *tmp = (WORD *)&name.string[i * 2];
1118 ret[i] = GET_BE_WORD(*tmp);
1120 ret[i] = 0;
1121 TRACE("Got localised name %s\n", debugstr_w(ret));
1124 return ret;
1128 /*****************************************************************
1129 * load_sfnt_table
1131 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1132 * of FreeType that don't export this function.
1135 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1138 FT_Error err;
1140 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1141 if(pFT_Load_Sfnt_Table)
1143 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1145 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1146 else /* Do it the hard way */
1148 TT_Face tt_face = (TT_Face) ft_face;
1149 SFNT_Interface *sfnt;
1150 if (FT_Version.major==2 && FT_Version.minor==0)
1152 /* 2.0.x */
1153 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1155 else
1157 /* A field was added in the middle of the structure in 2.1.x */
1158 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1160 err = sfnt->load_any(tt_face, table, offset, buf, len);
1162 #else
1163 else
1165 static int msg;
1166 if(!msg)
1168 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1169 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1170 "Please upgrade your freetype library.\n");
1171 msg++;
1173 err = FT_Err_Unimplemented_Feature;
1175 #endif
1176 return err;
1179 static inline int TestStyles(DWORD flags, DWORD styles)
1181 return (flags & styles) == styles;
1184 static int StyleOrdering(Face *face)
1186 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1187 return 3;
1188 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1189 return 2;
1190 if (TestStyles(face->ntmFlags, NTM_BOLD))
1191 return 1;
1192 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1193 return 0;
1195 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1196 debugstr_w(face->family->FamilyName),
1197 debugstr_w(face->StyleName),
1198 face->ntmFlags);
1200 return 9999;
1203 /* Add a style of face to a font family using an ordering of the list such
1204 that regular fonts come before bold and italic, and single styles come
1205 before compound styles. */
1206 static void AddFaceToFamily(Face *face, Family *family)
1208 struct list *entry;
1210 LIST_FOR_EACH( entry, &family->faces )
1212 Face *ent = LIST_ENTRY(entry, Face, entry);
1213 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1215 list_add_before( entry, &face->entry );
1218 #define ADDFONT_EXTERNAL_FONT 0x01
1219 #define ADDFONT_FORCE_BITMAP 0x02
1220 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1222 FT_Face ft_face;
1223 TT_OS2 *pOS2;
1224 TT_Header *pHeader = NULL;
1225 WCHAR *english_family, *localised_family, *StyleW;
1226 DWORD len;
1227 Family *family;
1228 Face *face;
1229 struct list *family_elem_ptr, *face_elem_ptr;
1230 FT_Error err;
1231 FT_Long face_index = 0, num_faces;
1232 #ifdef HAVE_FREETYPE_FTWINFNT_H
1233 FT_WinFNT_HeaderRec winfnt_header;
1234 #endif
1235 int i, bitmap_num, internal_leading;
1236 FONTSIGNATURE fs;
1238 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1239 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1241 #ifdef HAVE_CARBON_CARBON_H
1242 if(file && !fake_family)
1244 char **mac_list = expand_mac_font(file);
1245 if(mac_list)
1247 BOOL had_one = FALSE;
1248 char **cursor;
1249 for(cursor = mac_list; *cursor; cursor++)
1251 had_one = TRUE;
1252 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1253 HeapFree(GetProcessHeap(), 0, *cursor);
1255 HeapFree(GetProcessHeap(), 0, mac_list);
1256 if(had_one)
1257 return 1;
1260 #endif /* HAVE_CARBON_CARBON_H */
1262 do {
1263 char *family_name = fake_family;
1265 if (file)
1267 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1268 err = pFT_New_Face(library, file, face_index, &ft_face);
1269 } else
1271 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1272 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1275 if(err != 0) {
1276 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1277 return 0;
1280 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*/
1281 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1282 pFT_Done_Face(ft_face);
1283 return 0;
1286 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1287 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1288 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1289 pFT_Done_Face(ft_face);
1290 return 0;
1293 if(FT_IS_SFNT(ft_face))
1295 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1296 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1297 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1299 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1300 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1301 pFT_Done_Face(ft_face);
1302 return 0;
1305 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1306 we don't want to load these. */
1307 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1309 FT_ULong len = 0;
1311 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1313 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1314 pFT_Done_Face(ft_face);
1315 return 0;
1320 if(!ft_face->family_name || !ft_face->style_name) {
1321 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1322 pFT_Done_Face(ft_face);
1323 return 0;
1326 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1328 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1329 pFT_Done_Face(ft_face);
1330 return 0;
1333 if (target_family)
1335 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1336 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1338 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1339 HeapFree(GetProcessHeap(), 0, localised_family);
1340 num_faces = ft_face->num_faces;
1341 pFT_Done_Face(ft_face);
1342 continue;
1344 HeapFree(GetProcessHeap(), 0, localised_family);
1347 if(!family_name)
1348 family_name = ft_face->family_name;
1350 bitmap_num = 0;
1351 do {
1352 My_FT_Bitmap_Size *size = NULL;
1353 FT_ULong tmp_size;
1355 if(!FT_IS_SCALABLE(ft_face))
1356 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1358 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1359 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1360 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1362 localised_family = NULL;
1363 if(!fake_family) {
1364 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1365 if(localised_family && !strcmpiW(localised_family, english_family)) {
1366 HeapFree(GetProcessHeap(), 0, localised_family);
1367 localised_family = NULL;
1371 family = NULL;
1372 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1373 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1374 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1375 break;
1376 family = NULL;
1378 if(!family) {
1379 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1380 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1381 list_init(&family->faces);
1382 list_add_tail(&font_list, &family->entry);
1384 if(localised_family) {
1385 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1386 subst->from.name = strdupW(english_family);
1387 subst->from.charset = -1;
1388 subst->to.name = strdupW(localised_family);
1389 subst->to.charset = -1;
1390 add_font_subst(&font_subst_list, subst, 0);
1393 HeapFree(GetProcessHeap(), 0, localised_family);
1394 HeapFree(GetProcessHeap(), 0, english_family);
1396 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1397 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1398 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1400 internal_leading = 0;
1401 memset(&fs, 0, sizeof(fs));
1403 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1404 if(pOS2) {
1405 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1406 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1407 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1408 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1409 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1410 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1411 if(pOS2->version == 0) {
1412 FT_UInt dummy;
1414 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1415 fs.fsCsb[0] |= FS_LATIN1;
1416 else
1417 fs.fsCsb[0] |= FS_SYMBOL;
1420 #ifdef HAVE_FREETYPE_FTWINFNT_H
1421 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1422 CHARSETINFO csi;
1423 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1424 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1425 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1426 fs = csi.fs;
1427 internal_leading = winfnt_header.internal_leading;
1429 #endif
1431 face_elem_ptr = list_head(&family->faces);
1432 while(face_elem_ptr) {
1433 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1434 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1435 if(!strcmpiW(face->StyleName, StyleW) &&
1436 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1437 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1438 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1439 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1441 if(fake_family) {
1442 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1443 HeapFree(GetProcessHeap(), 0, StyleW);
1444 pFT_Done_Face(ft_face);
1445 return 1;
1447 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1448 TRACE("Original font is newer so skipping this one\n");
1449 HeapFree(GetProcessHeap(), 0, StyleW);
1450 pFT_Done_Face(ft_face);
1451 return 1;
1452 } else {
1453 TRACE("Replacing original with this one\n");
1454 list_remove(&face->entry);
1455 HeapFree(GetProcessHeap(), 0, face->file);
1456 HeapFree(GetProcessHeap(), 0, face->StyleName);
1457 HeapFree(GetProcessHeap(), 0, face->FullName);
1458 HeapFree(GetProcessHeap(), 0, face);
1459 break;
1463 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1464 face->cached_enum_data = NULL;
1465 face->StyleName = StyleW;
1466 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1467 if (file)
1469 face->file = strdupA(file);
1470 face->font_data_ptr = NULL;
1471 face->font_data_size = 0;
1473 else
1475 face->file = NULL;
1476 face->font_data_ptr = font_data_ptr;
1477 face->font_data_size = font_data_size;
1479 face->face_index = face_index;
1480 face->ntmFlags = 0;
1481 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1482 face->ntmFlags |= NTM_ITALIC;
1483 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1484 face->ntmFlags |= NTM_BOLD;
1485 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1486 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1487 face->family = family;
1488 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1489 face->fs = fs;
1490 memset(&face->fs_links, 0, sizeof(face->fs_links));
1492 if(FT_IS_SCALABLE(ft_face)) {
1493 memset(&face->size, 0, sizeof(face->size));
1494 face->scalable = TRUE;
1495 } else {
1496 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1497 size->height, size->width, size->size >> 6,
1498 size->x_ppem >> 6, size->y_ppem >> 6);
1499 face->size.height = size->height;
1500 face->size.width = size->width;
1501 face->size.size = size->size;
1502 face->size.x_ppem = size->x_ppem;
1503 face->size.y_ppem = size->y_ppem;
1504 face->size.internal_leading = internal_leading;
1505 face->scalable = FALSE;
1508 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1509 tmp_size = 0;
1510 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1512 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1513 face->ntmFlags |= NTM_PS_OPENTYPE;
1516 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1517 face->fs.fsCsb[0], face->fs.fsCsb[1],
1518 face->fs.fsUsb[0], face->fs.fsUsb[1],
1519 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1522 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1523 for(i = 0; i < ft_face->num_charmaps; i++) {
1524 switch(ft_face->charmaps[i]->encoding) {
1525 case FT_ENCODING_UNICODE:
1526 case FT_ENCODING_APPLE_ROMAN:
1527 face->fs.fsCsb[0] |= FS_LATIN1;
1528 break;
1529 case FT_ENCODING_MS_SYMBOL:
1530 face->fs.fsCsb[0] |= FS_SYMBOL;
1531 break;
1532 default:
1533 break;
1538 AddFaceToFamily(face, family);
1540 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1542 num_faces = ft_face->num_faces;
1543 pFT_Done_Face(ft_face);
1544 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1545 debugstr_w(StyleW));
1546 } while(num_faces > ++face_index);
1547 return num_faces;
1550 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1552 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1555 static void DumpFontList(void)
1557 Family *family;
1558 Face *face;
1559 struct list *family_elem_ptr, *face_elem_ptr;
1561 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1562 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1563 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1564 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1565 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1566 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1567 if(!face->scalable)
1568 TRACE(" %d", face->size.height);
1569 TRACE("\n");
1572 return;
1575 /***********************************************************
1576 * The replacement list is a way to map an entire font
1577 * family onto another family. For example adding
1579 * [HKCU\Software\Wine\Fonts\Replacements]
1580 * "Wingdings"="Winedings"
1582 * would enumerate the Winedings font both as Winedings and
1583 * Wingdings. However if a real Wingdings font is present the
1584 * replacement does not take place.
1587 static void LoadReplaceList(void)
1589 HKEY hkey;
1590 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1591 LPWSTR value;
1592 LPVOID data;
1593 Family *family;
1594 Face *face;
1595 struct list *family_elem_ptr, *face_elem_ptr;
1596 CHAR familyA[400];
1598 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1599 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1601 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1602 &valuelen, &datalen, NULL, NULL);
1604 valuelen++; /* returned value doesn't include room for '\0' */
1605 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1606 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1608 dlen = datalen;
1609 vlen = valuelen;
1610 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1611 &dlen) == ERROR_SUCCESS) {
1612 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1613 /* "NewName"="Oldname" */
1614 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1616 if(!find_family_from_name(value))
1618 /* Find the old family and hence all of the font files
1619 in that family */
1620 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1621 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1622 if(!strcmpiW(family->FamilyName, data)) {
1623 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1624 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1625 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1626 debugstr_w(face->StyleName), familyA);
1627 /* Now add a new entry with the new family name */
1628 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1629 familyA, family->FamilyName,
1630 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1632 break;
1636 /* reset dlen and vlen */
1637 dlen = datalen;
1638 vlen = valuelen;
1640 HeapFree(GetProcessHeap(), 0, data);
1641 HeapFree(GetProcessHeap(), 0, value);
1642 RegCloseKey(hkey);
1646 /*************************************************************
1647 * init_system_links
1649 static BOOL init_system_links(void)
1651 HKEY hkey;
1652 BOOL ret = FALSE;
1653 DWORD type, max_val, max_data, val_len, data_len, index;
1654 WCHAR *value, *data;
1655 WCHAR *entry, *next;
1656 SYSTEM_LINKS *font_link, *system_font_link;
1657 CHILD_FONT *child_font;
1658 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1659 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1660 FONTSIGNATURE fs;
1661 Family *family;
1662 Face *face;
1663 FontSubst *psub;
1665 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1667 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1668 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1669 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1670 val_len = max_val + 1;
1671 data_len = max_data;
1672 index = 0;
1673 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1675 memset(&fs, 0, sizeof(fs));
1676 psub = get_font_subst(&font_subst_list, value, -1);
1677 /* Don't store fonts that are only substitutes for other fonts */
1678 if(psub)
1680 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1681 goto next;
1683 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1684 font_link->font_name = strdupW(value);
1685 list_init(&font_link->links);
1686 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1688 WCHAR *face_name;
1689 CHILD_FONT *child_font;
1691 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1693 next = entry + strlenW(entry) + 1;
1695 face_name = strchrW(entry, ',');
1696 if(face_name)
1698 *face_name++ = 0;
1699 while(isspaceW(*face_name))
1700 face_name++;
1702 psub = get_font_subst(&font_subst_list, face_name, -1);
1703 if(psub)
1704 face_name = psub->to.name;
1706 face = find_face_from_filename(entry, face_name);
1707 if(!face)
1709 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1710 continue;
1713 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1714 child_font->face = face;
1715 child_font->font = NULL;
1716 fs.fsCsb[0] |= face->fs.fsCsb[0];
1717 fs.fsCsb[1] |= face->fs.fsCsb[1];
1718 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1719 list_add_tail(&font_link->links, &child_font->entry);
1721 family = find_family_from_name(font_link->font_name);
1722 if(family)
1724 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1726 face->fs_links = fs;
1729 list_add_tail(&system_links, &font_link->entry);
1730 next:
1731 val_len = max_val + 1;
1732 data_len = max_data;
1735 HeapFree(GetProcessHeap(), 0, value);
1736 HeapFree(GetProcessHeap(), 0, data);
1737 RegCloseKey(hkey);
1740 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1741 that Tahoma has */
1743 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1744 system_font_link->font_name = strdupW(System);
1745 list_init(&system_font_link->links);
1747 face = find_face_from_filename(tahoma_ttf, Tahoma);
1748 if(face)
1750 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1751 child_font->face = face;
1752 child_font->font = NULL;
1753 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1754 list_add_tail(&system_font_link->links, &child_font->entry);
1756 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1758 if(!strcmpiW(font_link->font_name, Tahoma))
1760 CHILD_FONT *font_link_entry;
1761 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1763 CHILD_FONT *new_child;
1764 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1765 new_child->face = font_link_entry->face;
1766 new_child->font = NULL;
1767 list_add_tail(&system_font_link->links, &new_child->entry);
1769 break;
1772 list_add_tail(&system_links, &system_font_link->entry);
1773 return ret;
1776 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1778 DIR *dir;
1779 struct dirent *dent;
1780 char path[MAX_PATH];
1782 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1784 dir = opendir(dirname);
1785 if(!dir) {
1786 WARN("Can't open directory %s\n", debugstr_a(dirname));
1787 return FALSE;
1789 while((dent = readdir(dir)) != NULL) {
1790 struct stat statbuf;
1792 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1793 continue;
1795 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1797 sprintf(path, "%s/%s", dirname, dent->d_name);
1799 if(stat(path, &statbuf) == -1)
1801 WARN("Can't stat %s\n", debugstr_a(path));
1802 continue;
1804 if(S_ISDIR(statbuf.st_mode))
1805 ReadFontDir(path, external_fonts);
1806 else
1807 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1809 closedir(dir);
1810 return TRUE;
1813 static void load_fontconfig_fonts(void)
1815 #ifdef SONAME_LIBFONTCONFIG
1816 void *fc_handle = NULL;
1817 FcConfig *config;
1818 FcPattern *pat;
1819 FcObjectSet *os;
1820 FcFontSet *fontset;
1821 int i, len;
1822 char *file;
1823 const char *ext;
1825 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1826 if(!fc_handle) {
1827 TRACE("Wine cannot find the fontconfig library (%s).\n",
1828 SONAME_LIBFONTCONFIG);
1829 return;
1831 #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;}
1832 LOAD_FUNCPTR(FcConfigGetCurrent);
1833 LOAD_FUNCPTR(FcFontList);
1834 LOAD_FUNCPTR(FcFontSetDestroy);
1835 LOAD_FUNCPTR(FcInit);
1836 LOAD_FUNCPTR(FcObjectSetAdd);
1837 LOAD_FUNCPTR(FcObjectSetCreate);
1838 LOAD_FUNCPTR(FcObjectSetDestroy);
1839 LOAD_FUNCPTR(FcPatternCreate);
1840 LOAD_FUNCPTR(FcPatternDestroy);
1841 LOAD_FUNCPTR(FcPatternGetBool);
1842 LOAD_FUNCPTR(FcPatternGetString);
1843 #undef LOAD_FUNCPTR
1845 if(!pFcInit()) return;
1847 config = pFcConfigGetCurrent();
1848 pat = pFcPatternCreate();
1849 os = pFcObjectSetCreate();
1850 pFcObjectSetAdd(os, FC_FILE);
1851 pFcObjectSetAdd(os, FC_SCALABLE);
1852 fontset = pFcFontList(config, pat, os);
1853 if(!fontset) return;
1854 for(i = 0; i < fontset->nfont; i++) {
1855 FcBool scalable;
1857 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1858 continue;
1859 TRACE("fontconfig: %s\n", file);
1861 /* We're just interested in OT/TT fonts for now, so this hack just
1862 picks up the scalable fonts without extensions .pf[ab] to save time
1863 loading every other font */
1865 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1867 TRACE("not scalable\n");
1868 continue;
1871 len = strlen( file );
1872 if(len < 4) continue;
1873 ext = &file[ len - 3 ];
1874 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1875 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1877 pFcFontSetDestroy(fontset);
1878 pFcObjectSetDestroy(os);
1879 pFcPatternDestroy(pat);
1880 sym_not_found:
1881 #endif
1882 return;
1885 static BOOL load_font_from_data_dir(LPCWSTR file)
1887 BOOL ret = FALSE;
1888 const char *data_dir = wine_get_data_dir();
1890 if (!data_dir) data_dir = wine_get_build_dir();
1892 if (data_dir)
1894 INT len;
1895 char *unix_name;
1897 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1899 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1901 strcpy(unix_name, data_dir);
1902 strcat(unix_name, "/fonts/");
1904 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1906 EnterCriticalSection( &freetype_cs );
1907 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1908 LeaveCriticalSection( &freetype_cs );
1909 HeapFree(GetProcessHeap(), 0, unix_name);
1911 return ret;
1914 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1916 static const WCHAR slashW[] = {'\\','\0'};
1917 BOOL ret = FALSE;
1918 WCHAR windowsdir[MAX_PATH];
1919 char *unixname;
1921 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1922 strcatW(windowsdir, fontsW);
1923 strcatW(windowsdir, slashW);
1924 strcatW(windowsdir, file);
1925 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1926 EnterCriticalSection( &freetype_cs );
1927 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1928 LeaveCriticalSection( &freetype_cs );
1929 HeapFree(GetProcessHeap(), 0, unixname);
1931 return ret;
1934 static void load_system_fonts(void)
1936 HKEY hkey;
1937 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1938 const WCHAR * const *value;
1939 DWORD dlen, type;
1940 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1941 char *unixname;
1943 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1944 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1945 strcatW(windowsdir, fontsW);
1946 for(value = SystemFontValues; *value; value++) {
1947 dlen = sizeof(data);
1948 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1949 type == REG_SZ) {
1950 BOOL added = FALSE;
1952 sprintfW(pathW, fmtW, windowsdir, data);
1953 if((unixname = wine_get_unix_file_name(pathW))) {
1954 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1955 HeapFree(GetProcessHeap(), 0, unixname);
1957 if (!added)
1958 load_font_from_data_dir(data);
1961 RegCloseKey(hkey);
1965 /*************************************************************
1967 * This adds registry entries for any externally loaded fonts
1968 * (fonts from fontconfig or FontDirs). It also deletes entries
1969 * of no longer existing fonts.
1972 static void update_reg_entries(void)
1974 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1975 LPWSTR valueW;
1976 DWORD len, len_fam;
1977 Family *family;
1978 Face *face;
1979 struct list *family_elem_ptr, *face_elem_ptr;
1980 WCHAR *file;
1981 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1982 static const WCHAR spaceW[] = {' ', '\0'};
1983 char *path;
1985 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1986 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1987 ERR("Can't create Windows font reg key\n");
1988 goto end;
1991 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1992 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1993 ERR("Can't create Windows font reg key\n");
1994 goto end;
1997 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1998 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1999 ERR("Can't create external font reg key\n");
2000 goto end;
2003 /* enumerate the fonts and add external ones to the two keys */
2005 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2006 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2007 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2008 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2009 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2010 if(!face->external) continue;
2011 len = len_fam;
2012 if (!(face->ntmFlags & NTM_REGULAR))
2013 len = len_fam + strlenW(face->StyleName) + 1;
2014 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2015 strcpyW(valueW, family->FamilyName);
2016 if(len != len_fam) {
2017 strcatW(valueW, spaceW);
2018 strcatW(valueW, face->StyleName);
2020 strcatW(valueW, TrueType);
2022 file = wine_get_dos_file_name(face->file);
2023 if(file)
2024 len = strlenW(file) + 1;
2025 else
2027 if((path = strrchr(face->file, '/')) == NULL)
2028 path = face->file;
2029 else
2030 path++;
2031 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2033 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2034 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2036 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2037 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2038 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2040 HeapFree(GetProcessHeap(), 0, file);
2041 HeapFree(GetProcessHeap(), 0, valueW);
2044 end:
2045 if(external_key) RegCloseKey(external_key);
2046 if(win9x_key) RegCloseKey(win9x_key);
2047 if(winnt_key) RegCloseKey(winnt_key);
2048 return;
2051 static void delete_external_font_keys(void)
2053 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2054 DWORD dlen, vlen, datalen, valuelen, i, type;
2055 LPWSTR valueW;
2056 LPVOID data;
2058 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2059 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2060 ERR("Can't create Windows font reg key\n");
2061 goto end;
2064 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2065 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2066 ERR("Can't create Windows font reg key\n");
2067 goto end;
2070 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2071 ERR("Can't create external font reg key\n");
2072 goto end;
2075 /* Delete all external fonts added last time */
2077 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2078 &valuelen, &datalen, NULL, NULL);
2079 valuelen++; /* returned value doesn't include room for '\0' */
2080 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2081 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2083 dlen = datalen * sizeof(WCHAR);
2084 vlen = valuelen;
2085 i = 0;
2086 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2087 &dlen) == ERROR_SUCCESS) {
2089 RegDeleteValueW(winnt_key, valueW);
2090 RegDeleteValueW(win9x_key, valueW);
2091 /* reset dlen and vlen */
2092 dlen = datalen;
2093 vlen = valuelen;
2095 HeapFree(GetProcessHeap(), 0, data);
2096 HeapFree(GetProcessHeap(), 0, valueW);
2098 /* Delete the old external fonts key */
2099 RegCloseKey(external_key);
2100 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2102 end:
2103 if(win9x_key) RegCloseKey(win9x_key);
2104 if(winnt_key) RegCloseKey(winnt_key);
2107 /*************************************************************
2108 * WineEngAddFontResourceEx
2111 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2113 INT ret = 0;
2115 GDI_CheckNotLock();
2117 if (ft_handle) /* do it only if we have freetype up and running */
2119 char *unixname;
2121 if(flags)
2122 FIXME("Ignoring flags %x\n", flags);
2124 if((unixname = wine_get_unix_file_name(file)))
2126 EnterCriticalSection( &freetype_cs );
2127 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2128 LeaveCriticalSection( &freetype_cs );
2129 HeapFree(GetProcessHeap(), 0, unixname);
2131 if (!ret && !strchrW(file, '\\')) {
2132 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2133 ret = load_font_from_winfonts_dir(file);
2134 if (!ret) {
2135 /* Try in datadir/fonts (or builddir/fonts),
2136 * needed for Magic the Gathering Online
2138 ret = load_font_from_data_dir(file);
2142 return ret;
2145 /*************************************************************
2146 * WineEngAddFontMemResourceEx
2149 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2151 GDI_CheckNotLock();
2153 if (ft_handle) /* do it only if we have freetype up and running */
2155 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2157 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2158 memcpy(pFontCopy, pbFont, cbFont);
2160 EnterCriticalSection( &freetype_cs );
2161 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2162 LeaveCriticalSection( &freetype_cs );
2164 if (*pcFonts == 0)
2166 TRACE("AddFontToList failed\n");
2167 HeapFree(GetProcessHeap(), 0, pFontCopy);
2168 return 0;
2170 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2171 * For now return something unique but quite random
2173 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2174 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2177 *pcFonts = 0;
2178 return 0;
2181 /*************************************************************
2182 * WineEngRemoveFontResourceEx
2185 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2187 GDI_CheckNotLock();
2188 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2189 return TRUE;
2192 static const struct nls_update_font_list
2194 UINT ansi_cp, oem_cp;
2195 const char *oem, *fixed, *system;
2196 const char *courier, *serif, *small, *sserif;
2197 /* these are for font substitutes */
2198 const char *shelldlg, *tmsrmn;
2199 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2200 *helv_0, *tmsrmn_0;
2201 const struct subst
2203 const char *from, *to;
2204 } arial_0, courier_new_0, times_new_roman_0;
2205 } nls_update_font_list[] =
2207 /* Latin 1 (United States) */
2208 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2209 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2210 "Tahoma","Times New Roman",
2211 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2212 { 0 }, { 0 }, { 0 }
2214 /* Latin 1 (Multilingual) */
2215 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2216 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2217 "Tahoma","Times New Roman", /* FIXME unverified */
2218 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2219 { 0 }, { 0 }, { 0 }
2221 /* Eastern Europe */
2222 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2223 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2224 "Tahoma","Times New Roman", /* FIXME unverified */
2225 "Fixedsys,238", "System,238",
2226 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2227 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2228 { "Arial CE,0", "Arial,238" },
2229 { "Courier New CE,0", "Courier New,238" },
2230 { "Times New Roman CE,0", "Times New Roman,238" }
2232 /* Cyrillic */
2233 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2234 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2235 "Tahoma","Times New Roman", /* FIXME unverified */
2236 "Fixedsys,204", "System,204",
2237 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2238 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2239 { "Arial Cyr,0", "Arial,204" },
2240 { "Courier New Cyr,0", "Courier New,204" },
2241 { "Times New Roman Cyr,0", "Times New Roman,204" }
2243 /* Greek */
2244 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2245 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2246 "Tahoma","Times New Roman", /* FIXME unverified */
2247 "Fixedsys,161", "System,161",
2248 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2249 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2250 { "Arial Greek,0", "Arial,161" },
2251 { "Courier New Greek,0", "Courier New,161" },
2252 { "Times New Roman Greek,0", "Times New Roman,161" }
2254 /* Turkish */
2255 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2256 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2257 "Tahoma","Times New Roman", /* FIXME unverified */
2258 "Fixedsys,162", "System,162",
2259 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2260 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2261 { "Arial Tur,0", "Arial,162" },
2262 { "Courier New Tur,0", "Courier New,162" },
2263 { "Times New Roman Tur,0", "Times New Roman,162" }
2265 /* Hebrew */
2266 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2267 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2268 "Tahoma","Times New Roman", /* FIXME unverified */
2269 "Fixedsys,177", "System,177",
2270 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2271 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2272 { 0 }, { 0 }, { 0 }
2274 /* Arabic */
2275 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2276 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2277 "Tahoma","Times New Roman", /* FIXME unverified */
2278 "Fixedsys,178", "System,178",
2279 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2280 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2281 { 0 }, { 0 }, { 0 }
2283 /* Baltic */
2284 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2285 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2286 "Tahoma","Times New Roman", /* FIXME unverified */
2287 "Fixedsys,186", "System,186",
2288 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2289 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2290 { "Arial Baltic,0", "Arial,186" },
2291 { "Courier New Baltic,0", "Courier New,186" },
2292 { "Times New Roman Baltic,0", "Times New Roman,186" }
2294 /* Vietnamese */
2295 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2296 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2297 "Tahoma","Times New Roman", /* FIXME unverified */
2298 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2299 { 0 }, { 0 }, { 0 }
2301 /* Thai */
2302 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2303 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2304 "Tahoma","Times New Roman", /* FIXME unverified */
2305 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2306 { 0 }, { 0 }, { 0 }
2308 /* Japanese */
2309 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2310 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2311 "MS UI Gothic","MS Serif",
2312 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2313 { 0 }, { 0 }, { 0 }
2315 /* Chinese Simplified */
2316 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2317 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2318 "SimSun", "NSimSun",
2319 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2320 { 0 }, { 0 }, { 0 }
2322 /* Korean */
2323 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2324 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2325 "Gulim", "Batang",
2326 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2327 { 0 }, { 0 }, { 0 }
2329 /* Chinese Traditional */
2330 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2331 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2332 "PMingLiU", "MingLiU",
2333 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2334 { 0 }, { 0 }, { 0 }
2338 static const WCHAR *font_links_list[] =
2340 Lucida_Sans_Unicode,
2341 Microsoft_Sans_Serif,
2342 Tahoma
2345 static const struct font_links_defaults_list
2347 /* Keyed off substitution for "MS Shell Dlg" */
2348 const WCHAR *shelldlg;
2349 /* Maximum of four substitutes, plus terminating NULL pointer */
2350 const WCHAR *substitutes[5];
2351 } font_links_defaults_list[] =
2353 /* Non East-Asian */
2354 { Tahoma, /* FIXME unverified ordering */
2355 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2357 /* Below lists are courtesy of
2358 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2360 /* Japanese */
2361 { MS_UI_Gothic,
2362 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2364 /* Chinese Simplified */
2365 { SimSun,
2366 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2368 /* Korean */
2369 { Gulim,
2370 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2372 /* Chinese Traditional */
2373 { PMingLiU,
2374 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2378 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2380 return ( ansi_cp == 932 /* CP932 for Japanese */
2381 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2382 || ansi_cp == 949 /* CP949 for Korean */
2383 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2386 static inline HKEY create_fonts_NT_registry_key(void)
2388 HKEY hkey = 0;
2390 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2391 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2392 return hkey;
2395 static inline HKEY create_fonts_9x_registry_key(void)
2397 HKEY hkey = 0;
2399 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2400 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2401 return hkey;
2404 static inline HKEY create_config_fonts_registry_key(void)
2406 HKEY hkey = 0;
2408 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2409 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2410 return hkey;
2413 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2415 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2416 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2417 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2418 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2421 static void set_value_key(HKEY hkey, const char *name, const char *value)
2423 if (value)
2424 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2425 else if (name)
2426 RegDeleteValueA(hkey, name);
2429 static void update_font_info(void)
2431 char buf[40], cpbuf[40];
2432 DWORD len, type;
2433 HKEY hkey = 0;
2434 UINT i, ansi_cp = 0, oem_cp = 0;
2435 BOOL done = FALSE;
2437 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2438 return;
2440 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2441 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2442 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2443 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2444 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2446 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2447 if (is_dbcs_ansi_cp(ansi_cp))
2448 use_default_fallback = TRUE;
2450 len = sizeof(buf);
2451 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2453 if (!strcmp( buf, cpbuf )) /* already set correctly */
2455 RegCloseKey(hkey);
2456 return;
2458 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2460 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2462 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2463 RegCloseKey(hkey);
2465 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2467 HKEY hkey;
2469 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2470 nls_update_font_list[i].oem_cp == oem_cp)
2472 hkey = create_config_fonts_registry_key();
2473 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2474 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2475 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2476 RegCloseKey(hkey);
2478 hkey = create_fonts_NT_registry_key();
2479 add_font_list(hkey, &nls_update_font_list[i]);
2480 RegCloseKey(hkey);
2482 hkey = create_fonts_9x_registry_key();
2483 add_font_list(hkey, &nls_update_font_list[i]);
2484 RegCloseKey(hkey);
2486 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2488 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2489 strlen(nls_update_font_list[i].shelldlg)+1);
2490 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2491 strlen(nls_update_font_list[i].tmsrmn)+1);
2493 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2494 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2495 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2496 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2497 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2498 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2499 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2500 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2502 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2503 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2504 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2506 RegCloseKey(hkey);
2508 done = TRUE;
2510 else
2512 /* Delete the FontSubstitutes from other locales */
2513 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2515 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2516 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2517 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2518 RegCloseKey(hkey);
2522 if (!done)
2523 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2525 /* Clear out system links */
2526 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2529 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2531 const WCHAR *value;
2532 int i;
2533 FontSubst *psub;
2534 Family *family;
2535 Face *face;
2536 const char *file;
2537 WCHAR *fileW;
2538 int fileLen;
2539 WCHAR buff[MAX_PATH];
2540 WCHAR *data;
2541 int entryLen;
2543 static const WCHAR comma[] = {',',0};
2545 RegDeleteValueW(hkey, name);
2546 if (values)
2548 data = buff;
2549 data[0] = '\0';
2550 for (i = 0; values[i] != NULL; i++)
2552 value = values[i];
2553 if (!strcmpiW(name,value))
2554 continue;
2555 psub = get_font_subst(&font_subst_list, value, -1);
2556 if(psub)
2557 value = psub->to.name;
2558 family = find_family_from_name(value);
2559 if (!family)
2560 continue;
2561 file = NULL;
2562 /* Use first extant filename for this Family */
2563 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2565 if (!face->file)
2566 continue;
2567 file = strrchr(face->file, '/');
2568 if (!file)
2569 file = face->file;
2570 else
2571 file++;
2572 break;
2574 if (!file)
2575 continue;
2576 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2577 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2578 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2579 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2580 if (sizeof(buff)-(data-buff) < entryLen + 1)
2582 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2583 HeapFree(GetProcessHeap(), 0, fileW);
2584 break;
2586 strcpyW(data, fileW);
2587 strcatW(data, comma);
2588 strcatW(data, value);
2589 data += entryLen;
2590 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2591 HeapFree(GetProcessHeap(), 0, fileW);
2593 if (data != buff)
2595 *data='\0';
2596 data++;
2597 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2598 } else
2599 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2600 } else
2601 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2604 static void update_system_links(void)
2606 HKEY hkey = 0;
2607 UINT i, j;
2608 BOOL done = FALSE;
2609 DWORD disposition;
2610 FontSubst *psub;
2612 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2614 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2616 if (disposition == REG_OPENED_EXISTING_KEY)
2618 TRACE("SystemLink key already exists, doing nothing\n");
2619 RegCloseKey(hkey);
2620 return;
2623 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2624 if (!psub) {
2625 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2626 RegCloseKey(hkey);
2627 return;
2630 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2632 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2634 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2635 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2637 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2638 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2639 done = TRUE;
2641 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2643 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2646 RegCloseKey(hkey);
2647 if (!done)
2648 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2649 } else
2650 WARN("failed to create SystemLink key\n");
2654 static BOOL init_freetype(void)
2656 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2657 if(!ft_handle) {
2658 WINE_MESSAGE(
2659 "Wine cannot find the FreeType font library. To enable Wine to\n"
2660 "use TrueType fonts please install a version of FreeType greater than\n"
2661 "or equal to 2.0.5.\n"
2662 "http://www.freetype.org\n");
2663 return FALSE;
2666 #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;}
2668 LOAD_FUNCPTR(FT_Vector_Unit)
2669 LOAD_FUNCPTR(FT_Done_Face)
2670 LOAD_FUNCPTR(FT_Get_Char_Index)
2671 LOAD_FUNCPTR(FT_Get_Module)
2672 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2673 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2674 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2675 LOAD_FUNCPTR(FT_Init_FreeType)
2676 LOAD_FUNCPTR(FT_Load_Glyph)
2677 LOAD_FUNCPTR(FT_Matrix_Multiply)
2678 #ifndef FT_MULFIX_INLINED
2679 LOAD_FUNCPTR(FT_MulFix)
2680 #endif
2681 LOAD_FUNCPTR(FT_New_Face)
2682 LOAD_FUNCPTR(FT_New_Memory_Face)
2683 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2684 LOAD_FUNCPTR(FT_Outline_Transform)
2685 LOAD_FUNCPTR(FT_Outline_Translate)
2686 LOAD_FUNCPTR(FT_Select_Charmap)
2687 LOAD_FUNCPTR(FT_Set_Charmap)
2688 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2689 LOAD_FUNCPTR(FT_Vector_Transform)
2690 LOAD_FUNCPTR(FT_Render_Glyph)
2692 #undef LOAD_FUNCPTR
2693 /* Don't warn if these ones are missing */
2694 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2695 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2696 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2697 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2698 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2699 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2700 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2701 #endif
2702 #ifdef HAVE_FREETYPE_FTWINFNT_H
2703 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2704 #endif
2705 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2706 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2707 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2708 <= 2.0.3 has FT_Sqrt64 */
2709 goto sym_not_found;
2712 if(pFT_Init_FreeType(&library) != 0) {
2713 ERR("Can't init FreeType library\n");
2714 wine_dlclose(ft_handle, NULL, 0);
2715 ft_handle = NULL;
2716 return FALSE;
2718 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2719 if (pFT_Library_Version)
2720 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2722 if (FT_Version.major<=0)
2724 FT_Version.major=2;
2725 FT_Version.minor=0;
2726 FT_Version.patch=5;
2728 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2729 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2730 ((FT_Version.minor << 8) & 0x00ff00) |
2731 ((FT_Version.patch ) & 0x0000ff);
2733 return TRUE;
2735 sym_not_found:
2736 WINE_MESSAGE(
2737 "Wine cannot find certain functions that it needs inside the FreeType\n"
2738 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2739 "FreeType to at least version 2.0.5.\n"
2740 "http://www.freetype.org\n");
2741 wine_dlclose(ft_handle, NULL, 0);
2742 ft_handle = NULL;
2743 return FALSE;
2746 /*************************************************************
2747 * WineEngInit
2749 * Initialize FreeType library and create a list of available faces
2751 BOOL WineEngInit(void)
2753 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2754 static const WCHAR pathW[] = {'P','a','t','h',0};
2755 HKEY hkey;
2756 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2757 WCHAR windowsdir[MAX_PATH];
2758 char *unixname;
2759 HANDLE font_mutex;
2760 const char *data_dir;
2762 TRACE("\n");
2764 /* update locale dependent font info in registry */
2765 update_font_info();
2767 if(!init_freetype()) return FALSE;
2769 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2770 ERR("Failed to create font mutex\n");
2771 return FALSE;
2773 WaitForSingleObject(font_mutex, INFINITE);
2775 delete_external_font_keys();
2777 /* load the system bitmap fonts */
2778 load_system_fonts();
2780 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2781 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2782 strcatW(windowsdir, fontsW);
2783 if((unixname = wine_get_unix_file_name(windowsdir)))
2785 ReadFontDir(unixname, FALSE);
2786 HeapFree(GetProcessHeap(), 0, unixname);
2789 /* load the system truetype fonts */
2790 data_dir = wine_get_data_dir();
2791 if (!data_dir) data_dir = wine_get_build_dir();
2792 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2793 strcpy(unixname, data_dir);
2794 strcat(unixname, "/fonts/");
2795 ReadFontDir(unixname, TRUE);
2796 HeapFree(GetProcessHeap(), 0, unixname);
2799 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2800 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2801 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2802 will skip these. */
2803 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2804 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2805 &hkey) == ERROR_SUCCESS) {
2806 LPWSTR data, valueW;
2807 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2808 &valuelen, &datalen, NULL, NULL);
2810 valuelen++; /* returned value doesn't include room for '\0' */
2811 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2812 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2813 if (valueW && data)
2815 dlen = datalen * sizeof(WCHAR);
2816 vlen = valuelen;
2817 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2818 &dlen) == ERROR_SUCCESS) {
2819 if(data[0] && (data[1] == ':'))
2821 if((unixname = wine_get_unix_file_name(data)))
2823 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2824 HeapFree(GetProcessHeap(), 0, unixname);
2827 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2829 WCHAR pathW[MAX_PATH];
2830 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2831 BOOL added = FALSE;
2833 sprintfW(pathW, fmtW, windowsdir, data);
2834 if((unixname = wine_get_unix_file_name(pathW)))
2836 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2837 HeapFree(GetProcessHeap(), 0, unixname);
2839 if (!added)
2840 load_font_from_data_dir(data);
2842 /* reset dlen and vlen */
2843 dlen = datalen;
2844 vlen = valuelen;
2847 HeapFree(GetProcessHeap(), 0, data);
2848 HeapFree(GetProcessHeap(), 0, valueW);
2849 RegCloseKey(hkey);
2852 load_fontconfig_fonts();
2854 /* then look in any directories that we've specified in the config file */
2855 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2856 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2858 DWORD len;
2859 LPWSTR valueW;
2860 LPSTR valueA, ptr;
2862 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2864 len += sizeof(WCHAR);
2865 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2866 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2868 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2869 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2870 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2871 TRACE( "got font path %s\n", debugstr_a(valueA) );
2872 ptr = valueA;
2873 while (ptr)
2875 LPSTR next = strchr( ptr, ':' );
2876 if (next) *next++ = 0;
2877 ReadFontDir( ptr, TRUE );
2878 ptr = next;
2880 HeapFree( GetProcessHeap(), 0, valueA );
2882 HeapFree( GetProcessHeap(), 0, valueW );
2884 RegCloseKey(hkey);
2887 DumpFontList();
2888 LoadSubstList();
2889 DumpSubstList();
2890 LoadReplaceList();
2891 update_reg_entries();
2893 update_system_links();
2894 init_system_links();
2896 ReleaseMutex(font_mutex);
2897 return TRUE;
2901 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2903 TT_OS2 *pOS2;
2904 TT_HoriHeader *pHori;
2906 LONG ppem;
2908 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2909 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2911 if(height == 0) height = 16;
2913 /* Calc. height of EM square:
2915 * For +ve lfHeight we have
2916 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2917 * Re-arranging gives:
2918 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2920 * For -ve lfHeight we have
2921 * |lfHeight| = ppem
2922 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2923 * with il = winAscent + winDescent - units_per_em]
2927 if(height > 0) {
2928 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2929 ppem = MulDiv(ft_face->units_per_EM, height,
2930 pHori->Ascender - pHori->Descender);
2931 else
2932 ppem = MulDiv(ft_face->units_per_EM, height,
2933 pOS2->usWinAscent + pOS2->usWinDescent);
2935 else
2936 ppem = -height;
2938 return ppem;
2941 static struct font_mapping *map_font_file( const char *name )
2943 struct font_mapping *mapping;
2944 struct stat st;
2945 int fd;
2947 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2948 if (fstat( fd, &st ) == -1) goto error;
2950 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2952 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2954 mapping->refcount++;
2955 close( fd );
2956 return mapping;
2959 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2960 goto error;
2962 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2963 close( fd );
2965 if (mapping->data == MAP_FAILED)
2967 HeapFree( GetProcessHeap(), 0, mapping );
2968 return NULL;
2970 mapping->refcount = 1;
2971 mapping->dev = st.st_dev;
2972 mapping->ino = st.st_ino;
2973 mapping->size = st.st_size;
2974 list_add_tail( &mappings_list, &mapping->entry );
2975 return mapping;
2977 error:
2978 close( fd );
2979 return NULL;
2982 static void unmap_font_file( struct font_mapping *mapping )
2984 if (!--mapping->refcount)
2986 list_remove( &mapping->entry );
2987 munmap( mapping->data, mapping->size );
2988 HeapFree( GetProcessHeap(), 0, mapping );
2992 static LONG load_VDMX(GdiFont*, LONG);
2994 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2996 FT_Error err;
2997 FT_Face ft_face;
2998 void *data_ptr;
2999 DWORD data_size;
3001 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3003 if (face->file)
3005 if (!(font->mapping = map_font_file( face->file )))
3007 WARN("failed to map %s\n", debugstr_a(face->file));
3008 return 0;
3010 data_ptr = font->mapping->data;
3011 data_size = font->mapping->size;
3013 else
3015 data_ptr = face->font_data_ptr;
3016 data_size = face->font_data_size;
3019 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3020 if(err) {
3021 ERR("FT_New_Face rets %d\n", err);
3022 return 0;
3025 /* set it here, as load_VDMX needs it */
3026 font->ft_face = ft_face;
3028 if(FT_IS_SCALABLE(ft_face)) {
3029 /* load the VDMX table if we have one */
3030 font->ppem = load_VDMX(font, height);
3031 if(font->ppem == 0)
3032 font->ppem = calc_ppem_for_height(ft_face, height);
3033 TRACE("height %d => ppem %d\n", height, font->ppem);
3035 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3036 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3037 } else {
3038 font->ppem = height;
3039 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3040 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3042 return ft_face;
3046 static int get_nearest_charset(Face *face, int *cp)
3048 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3049 a single face with the requested charset. The idea is to check if
3050 the selected font supports the current ANSI codepage, if it does
3051 return the corresponding charset, else return the first charset */
3053 CHARSETINFO csi;
3054 int acp = GetACP(), i;
3055 DWORD fs0;
3057 *cp = acp;
3058 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3059 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3060 return csi.ciCharset;
3062 for(i = 0; i < 32; i++) {
3063 fs0 = 1L << i;
3064 if(face->fs.fsCsb[0] & fs0) {
3065 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3066 *cp = csi.ciACP;
3067 return csi.ciCharset;
3069 else
3070 FIXME("TCI failing on %x\n", fs0);
3074 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3075 face->fs.fsCsb[0], face->file);
3076 *cp = acp;
3077 return DEFAULT_CHARSET;
3080 static GdiFont *alloc_font(void)
3082 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3083 ret->gmsize = 1;
3084 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3085 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3086 ret->potm = NULL;
3087 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3088 ret->total_kern_pairs = (DWORD)-1;
3089 ret->kern_pairs = NULL;
3090 list_init(&ret->hfontlist);
3091 list_init(&ret->child_fonts);
3092 return ret;
3095 static void free_font(GdiFont *font)
3097 struct list *cursor, *cursor2;
3098 DWORD i;
3100 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3102 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3103 list_remove(cursor);
3104 if(child->font)
3105 free_font(child->font);
3106 HeapFree(GetProcessHeap(), 0, child);
3109 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3111 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3112 DeleteObject(hfontlist->hfont);
3113 list_remove(&hfontlist->entry);
3114 HeapFree(GetProcessHeap(), 0, hfontlist);
3117 if (font->ft_face) pFT_Done_Face(font->ft_face);
3118 if (font->mapping) unmap_font_file( font->mapping );
3119 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3120 HeapFree(GetProcessHeap(), 0, font->potm);
3121 HeapFree(GetProcessHeap(), 0, font->name);
3122 for (i = 0; i < font->gmsize; i++)
3123 HeapFree(GetProcessHeap(),0,font->gm[i]);
3124 HeapFree(GetProcessHeap(), 0, font->gm);
3125 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3126 HeapFree(GetProcessHeap(), 0, font);
3130 /*************************************************************
3131 * load_VDMX
3133 * load the vdmx entry for the specified height
3136 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3137 ( ( (FT_ULong)_x4 << 24 ) | \
3138 ( (FT_ULong)_x3 << 16 ) | \
3139 ( (FT_ULong)_x2 << 8 ) | \
3140 (FT_ULong)_x1 )
3142 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3144 typedef struct {
3145 BYTE bCharSet;
3146 BYTE xRatio;
3147 BYTE yStartRatio;
3148 BYTE yEndRatio;
3149 } Ratios;
3151 typedef struct {
3152 WORD recs;
3153 BYTE startsz;
3154 BYTE endsz;
3155 } VDMX_group;
3157 static LONG load_VDMX(GdiFont *font, LONG height)
3159 WORD hdr[3], tmp;
3160 VDMX_group group;
3161 BYTE devXRatio, devYRatio;
3162 USHORT numRecs, numRatios;
3163 DWORD result, offset = -1;
3164 LONG ppem = 0;
3165 int i;
3167 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3169 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3170 return ppem;
3172 /* FIXME: need the real device aspect ratio */
3173 devXRatio = 1;
3174 devYRatio = 1;
3176 numRecs = GET_BE_WORD(hdr[1]);
3177 numRatios = GET_BE_WORD(hdr[2]);
3179 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3180 for(i = 0; i < numRatios; i++) {
3181 Ratios ratio;
3183 offset = (3 * 2) + (i * sizeof(Ratios));
3184 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3185 offset = -1;
3187 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3189 if((ratio.xRatio == 0 &&
3190 ratio.yStartRatio == 0 &&
3191 ratio.yEndRatio == 0) ||
3192 (devXRatio == ratio.xRatio &&
3193 devYRatio >= ratio.yStartRatio &&
3194 devYRatio <= ratio.yEndRatio))
3196 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3197 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3198 offset = GET_BE_WORD(tmp);
3199 break;
3203 if(offset == -1) {
3204 FIXME("No suitable ratio found\n");
3205 return ppem;
3208 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3209 USHORT recs;
3210 BYTE startsz, endsz;
3211 WORD *vTable;
3213 recs = GET_BE_WORD(group.recs);
3214 startsz = group.startsz;
3215 endsz = group.endsz;
3217 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3219 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3220 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3221 if(result == GDI_ERROR) {
3222 FIXME("Failed to retrieve vTable\n");
3223 goto end;
3226 if(height > 0) {
3227 for(i = 0; i < recs; i++) {
3228 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3229 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3230 ppem = GET_BE_WORD(vTable[i * 3]);
3232 if(yMax + -yMin == height) {
3233 font->yMax = yMax;
3234 font->yMin = yMin;
3235 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3236 break;
3238 if(yMax + -yMin > height) {
3239 if(--i < 0) {
3240 ppem = 0;
3241 goto end; /* failed */
3243 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3244 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3245 ppem = GET_BE_WORD(vTable[i * 3]);
3246 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3247 break;
3250 if(!font->yMax) {
3251 ppem = 0;
3252 TRACE("ppem not found for height %d\n", height);
3255 end:
3256 HeapFree(GetProcessHeap(), 0, vTable);
3259 return ppem;
3262 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3264 if(font->font_desc.hash != fd->hash) return TRUE;
3265 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3266 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3267 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3268 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3271 static void calc_hash(FONT_DESC *pfd)
3273 DWORD hash = 0, *ptr, two_chars;
3274 WORD *pwc;
3275 unsigned int i;
3277 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3278 hash ^= *ptr;
3279 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3280 hash ^= *ptr;
3281 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3282 two_chars = *ptr;
3283 pwc = (WCHAR *)&two_chars;
3284 if(!*pwc) break;
3285 *pwc = toupperW(*pwc);
3286 pwc++;
3287 *pwc = toupperW(*pwc);
3288 hash ^= two_chars;
3289 if(!*pwc) break;
3291 hash ^= !pfd->can_use_bitmap;
3292 pfd->hash = hash;
3293 return;
3296 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3298 GdiFont *ret;
3299 FONT_DESC fd;
3300 HFONTLIST *hflist;
3301 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3303 fd.lf = *plf;
3304 fd.matrix = *pmat;
3305 fd.can_use_bitmap = can_use_bitmap;
3306 calc_hash(&fd);
3308 /* try the child list */
3309 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3310 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3311 if(!fontcmp(ret, &fd)) {
3312 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3313 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3314 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3315 if(hflist->hfont == hfont)
3316 return ret;
3321 /* try the in-use list */
3322 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3323 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3324 if(!fontcmp(ret, &fd)) {
3325 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3326 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3327 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3328 if(hflist->hfont == hfont)
3329 return ret;
3331 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3332 hflist->hfont = hfont;
3333 list_add_head(&ret->hfontlist, &hflist->entry);
3334 return ret;
3338 /* then the unused list */
3339 font_elem_ptr = list_head(&unused_gdi_font_list);
3340 while(font_elem_ptr) {
3341 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3342 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3343 if(!fontcmp(ret, &fd)) {
3344 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3345 assert(list_empty(&ret->hfontlist));
3346 TRACE("Found %p in unused list\n", ret);
3347 list_remove(&ret->entry);
3348 list_add_head(&gdi_font_list, &ret->entry);
3349 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3350 hflist->hfont = hfont;
3351 list_add_head(&ret->hfontlist, &hflist->entry);
3352 return ret;
3355 return NULL;
3358 static void add_to_cache(GdiFont *font)
3360 static DWORD cache_num = 1;
3362 font->cache_num = cache_num++;
3363 list_add_head(&gdi_font_list, &font->entry);
3366 /*************************************************************
3367 * create_child_font_list
3369 static BOOL create_child_font_list(GdiFont *font)
3371 BOOL ret = FALSE;
3372 SYSTEM_LINKS *font_link;
3373 CHILD_FONT *font_link_entry, *new_child;
3374 FontSubst *psub;
3375 WCHAR* font_name;
3377 psub = get_font_subst(&font_subst_list, font->name, -1);
3378 font_name = psub ? psub->to.name : font->name;
3379 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3381 if(!strcmpiW(font_link->font_name, font_name))
3383 TRACE("found entry in system list\n");
3384 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3386 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3387 new_child->face = font_link_entry->face;
3388 new_child->font = NULL;
3389 list_add_tail(&font->child_fonts, &new_child->entry);
3390 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3392 ret = TRUE;
3393 break;
3397 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3398 * Sans Serif. This is how asian windows get default fallbacks for fonts
3400 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3401 font->charset != OEM_CHARSET &&
3402 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3403 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3405 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3407 TRACE("found entry in default fallback list\n");
3408 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3410 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3411 new_child->face = font_link_entry->face;
3412 new_child->font = NULL;
3413 list_add_tail(&font->child_fonts, &new_child->entry);
3414 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3416 ret = TRUE;
3417 break;
3421 return ret;
3424 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3426 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3428 if (pFT_Set_Charmap)
3430 FT_Int i;
3431 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3433 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3435 for (i = 0; i < ft_face->num_charmaps; i++)
3437 if (ft_face->charmaps[i]->encoding == encoding)
3439 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3440 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3442 switch (ft_face->charmaps[i]->platform_id)
3444 default:
3445 cmap_def = ft_face->charmaps[i];
3446 break;
3447 case 0: /* Apple Unicode */
3448 cmap0 = ft_face->charmaps[i];
3449 break;
3450 case 1: /* Macintosh */
3451 cmap1 = ft_face->charmaps[i];
3452 break;
3453 case 2: /* ISO */
3454 cmap2 = ft_face->charmaps[i];
3455 break;
3456 case 3: /* Microsoft */
3457 cmap3 = ft_face->charmaps[i];
3458 break;
3462 if (cmap3) /* prefer Microsoft cmap table */
3463 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3464 else if (cmap1)
3465 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3466 else if (cmap2)
3467 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3468 else if (cmap0)
3469 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3470 else if (cmap_def)
3471 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3473 return ft_err == FT_Err_Ok;
3476 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3479 /*************************************************************
3480 * WineEngCreateFontInstance
3483 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3485 GdiFont *ret;
3486 Face *face, *best, *best_bitmap;
3487 Family *family, *last_resort_family;
3488 struct list *family_elem_ptr, *face_elem_ptr;
3489 INT height, width = 0;
3490 unsigned int score = 0, new_score;
3491 signed int diff = 0, newdiff;
3492 BOOL bd, it, can_use_bitmap;
3493 LOGFONTW lf;
3494 CHARSETINFO csi;
3495 HFONTLIST *hflist;
3496 FMAT2 dcmat;
3497 FontSubst *psub = NULL;
3499 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3500 lf.lfWidth = abs(lf.lfWidth);
3502 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3504 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3505 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3506 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3507 lf.lfEscapement);
3509 if(dc->GraphicsMode == GM_ADVANCED)
3510 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3511 else
3513 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3514 font scaling abilities. */
3515 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3516 dcmat.eM21 = dcmat.eM12 = 0;
3519 /* Try to avoid not necessary glyph transformations */
3520 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3522 lf.lfHeight *= fabs(dcmat.eM11);
3523 lf.lfWidth *= fabs(dcmat.eM11);
3524 dcmat.eM11 = dcmat.eM22 = 1.0;
3527 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3528 dcmat.eM21, dcmat.eM22);
3530 GDI_CheckNotLock();
3531 EnterCriticalSection( &freetype_cs );
3533 /* check the cache first */
3534 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3535 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3536 LeaveCriticalSection( &freetype_cs );
3537 return ret;
3540 TRACE("not in cache\n");
3541 if(list_empty(&font_list)) /* No fonts installed */
3543 TRACE("No fonts installed\n");
3544 LeaveCriticalSection( &freetype_cs );
3545 return NULL;
3548 ret = alloc_font();
3550 ret->font_desc.matrix = dcmat;
3551 ret->font_desc.lf = lf;
3552 ret->font_desc.can_use_bitmap = can_use_bitmap;
3553 calc_hash(&ret->font_desc);
3554 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3555 hflist->hfont = hfont;
3556 list_add_head(&ret->hfontlist, &hflist->entry);
3558 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3559 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3560 original value lfCharSet. Note this is a special case for
3561 Symbol and doesn't happen at least for "Wingdings*" */
3563 if(!strcmpiW(lf.lfFaceName, SymbolW))
3564 lf.lfCharSet = SYMBOL_CHARSET;
3566 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3567 switch(lf.lfCharSet) {
3568 case DEFAULT_CHARSET:
3569 csi.fs.fsCsb[0] = 0;
3570 break;
3571 default:
3572 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3573 csi.fs.fsCsb[0] = 0;
3574 break;
3578 family = NULL;
3579 if(lf.lfFaceName[0] != '\0') {
3580 SYSTEM_LINKS *font_link;
3581 CHILD_FONT *font_link_entry;
3582 LPWSTR FaceName = lf.lfFaceName;
3585 * Check for a leading '@' this signals that the font is being
3586 * requested in tategaki mode (vertical writing substitution) but
3587 * does not affect the fontface that is to be selected.
3589 if (lf.lfFaceName[0]=='@')
3590 FaceName = &lf.lfFaceName[1];
3592 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3594 if(psub) {
3595 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3596 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3597 if (psub->to.charset != -1)
3598 lf.lfCharSet = psub->to.charset;
3601 /* We want a match on name and charset or just name if
3602 charset was DEFAULT_CHARSET. If the latter then
3603 we fixup the returned charset later in get_nearest_charset
3604 where we'll either use the charset of the current ansi codepage
3605 or if that's unavailable the first charset that the font supports.
3607 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3608 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3609 if (!strcmpiW(family->FamilyName, FaceName) ||
3610 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3612 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3613 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3614 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3615 if(face->scalable || can_use_bitmap)
3616 goto found;
3621 /* Search by full face name. */
3622 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3623 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3624 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3625 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3626 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3627 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3629 if(face->scalable || can_use_bitmap)
3630 goto found_face;
3636 * Try check the SystemLink list first for a replacement font.
3637 * We may find good replacements there.
3639 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3641 if(!strcmpiW(font_link->font_name, FaceName) ||
3642 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3644 TRACE("found entry in system list\n");
3645 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3647 face = font_link_entry->face;
3648 family = face->family;
3649 if(csi.fs.fsCsb[0] &
3650 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3652 if(face->scalable || can_use_bitmap)
3653 goto found;
3660 psub = NULL; /* substitution is no more relevant */
3662 /* If requested charset was DEFAULT_CHARSET then try using charset
3663 corresponding to the current ansi codepage */
3664 if (!csi.fs.fsCsb[0])
3666 INT acp = GetACP();
3667 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3668 FIXME("TCI failed on codepage %d\n", acp);
3669 csi.fs.fsCsb[0] = 0;
3670 } else
3671 lf.lfCharSet = csi.ciCharset;
3674 /* Face families are in the top 4 bits of lfPitchAndFamily,
3675 so mask with 0xF0 before testing */
3677 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3678 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3679 strcpyW(lf.lfFaceName, defFixed);
3680 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3681 strcpyW(lf.lfFaceName, defSerif);
3682 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3683 strcpyW(lf.lfFaceName, defSans);
3684 else
3685 strcpyW(lf.lfFaceName, defSans);
3686 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3687 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3688 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3689 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3690 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3691 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3692 if(face->scalable || can_use_bitmap)
3693 goto found;
3698 last_resort_family = NULL;
3699 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3700 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3701 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3702 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3703 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3704 if(face->scalable)
3705 goto found;
3706 if(can_use_bitmap && !last_resort_family)
3707 last_resort_family = family;
3712 if(last_resort_family) {
3713 family = last_resort_family;
3714 csi.fs.fsCsb[0] = 0;
3715 goto found;
3718 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3719 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3720 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3721 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3722 if(face->scalable) {
3723 csi.fs.fsCsb[0] = 0;
3724 WARN("just using first face for now\n");
3725 goto found;
3727 if(can_use_bitmap && !last_resort_family)
3728 last_resort_family = family;
3731 if(!last_resort_family) {
3732 FIXME("can't find a single appropriate font - bailing\n");
3733 free_font(ret);
3734 LeaveCriticalSection( &freetype_cs );
3735 return NULL;
3738 WARN("could only find a bitmap font - this will probably look awful!\n");
3739 family = last_resort_family;
3740 csi.fs.fsCsb[0] = 0;
3742 found:
3743 it = lf.lfItalic ? 1 : 0;
3744 bd = lf.lfWeight > 550 ? 1 : 0;
3746 height = lf.lfHeight;
3748 face = best = best_bitmap = NULL;
3749 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3751 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3753 BOOL italic, bold;
3755 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3756 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3757 new_score = (italic ^ it) + (bold ^ bd);
3758 if(!best || new_score <= score)
3760 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3761 italic, bold, it, bd);
3762 score = new_score;
3763 best = face;
3764 if(best->scalable && score == 0) break;
3765 if(!best->scalable)
3767 if(height > 0)
3768 newdiff = height - (signed int)(best->size.height);
3769 else
3770 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3771 if(!best_bitmap || new_score < score ||
3772 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3774 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3775 diff = newdiff;
3776 best_bitmap = best;
3777 if(score == 0 && diff == 0) break;
3783 if(best)
3784 face = best->scalable ? best : best_bitmap;
3785 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3786 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3788 found_face:
3789 height = lf.lfHeight;
3791 ret->fs = face->fs;
3793 if(csi.fs.fsCsb[0]) {
3794 ret->charset = lf.lfCharSet;
3795 ret->codepage = csi.ciACP;
3797 else
3798 ret->charset = get_nearest_charset(face, &ret->codepage);
3800 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3801 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3803 ret->aveWidth = height ? lf.lfWidth : 0;
3805 if(!face->scalable) {
3806 /* Windows uses integer scaling factors for bitmap fonts */
3807 INT scale, scaled_height;
3808 GdiFont *cachedfont;
3810 /* FIXME: rotation of bitmap fonts is ignored */
3811 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3812 if (ret->aveWidth)
3813 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3814 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3815 dcmat.eM11 = dcmat.eM22 = 1.0;
3816 /* As we changed the matrix, we need to search the cache for the font again,
3817 * otherwise we might explode the cache. */
3818 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3819 TRACE("Found cached font after non-scalable matrix rescale!\n");
3820 free_font( ret );
3821 LeaveCriticalSection( &freetype_cs );
3822 return cachedfont;
3824 calc_hash(&ret->font_desc);
3826 if (height != 0) height = diff;
3827 height += face->size.height;
3829 scale = (height + face->size.height - 1) / face->size.height;
3830 scaled_height = scale * face->size.height;
3831 /* Only jump to the next height if the difference <= 25% original height */
3832 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3833 /* The jump between unscaled and doubled is delayed by 1 */
3834 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3835 ret->scale_y = scale;
3837 width = face->size.x_ppem >> 6;
3838 height = face->size.y_ppem >> 6;
3840 else
3841 ret->scale_y = 1.0;
3842 TRACE("font scale y: %f\n", ret->scale_y);
3844 ret->ft_face = OpenFontFace(ret, face, width, height);
3846 if (!ret->ft_face)
3848 free_font( ret );
3849 LeaveCriticalSection( &freetype_cs );
3850 return 0;
3853 ret->ntmFlags = face->ntmFlags;
3855 if (ret->charset == SYMBOL_CHARSET &&
3856 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3857 /* No ops */
3859 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3860 /* No ops */
3862 else {
3863 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3866 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3867 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3868 ret->underline = lf.lfUnderline ? 0xff : 0;
3869 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3870 create_child_font_list(ret);
3872 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3874 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3875 if (length != GDI_ERROR)
3877 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3878 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3879 TRACE("Loaded GSUB table of %i bytes\n",length);
3883 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3885 add_to_cache(ret);
3886 LeaveCriticalSection( &freetype_cs );
3887 return ret;
3890 static void dump_gdi_font_list(void)
3892 GdiFont *gdiFont;
3893 struct list *elem_ptr;
3895 TRACE("---------- gdiFont Cache ----------\n");
3896 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3897 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3898 TRACE("gdiFont=%p %s %d\n",
3899 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3902 TRACE("---------- Unused gdiFont Cache ----------\n");
3903 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3904 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3905 TRACE("gdiFont=%p %s %d\n",
3906 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3909 TRACE("---------- Child gdiFont Cache ----------\n");
3910 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3911 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3912 TRACE("gdiFont=%p %s %d\n",
3913 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3917 /*************************************************************
3918 * WineEngDestroyFontInstance
3920 * free the gdiFont associated with this handle
3923 BOOL WineEngDestroyFontInstance(HFONT handle)
3925 GdiFont *gdiFont;
3926 HFONTLIST *hflist;
3927 BOOL ret = FALSE;
3928 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3929 int i = 0;
3931 GDI_CheckNotLock();
3932 EnterCriticalSection( &freetype_cs );
3934 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3936 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3937 while(hfontlist_elem_ptr) {
3938 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3939 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3940 if(hflist->hfont == handle) {
3941 TRACE("removing child font %p from child list\n", gdiFont);
3942 list_remove(&gdiFont->entry);
3943 LeaveCriticalSection( &freetype_cs );
3944 return TRUE;
3949 TRACE("destroying hfont=%p\n", handle);
3950 if(TRACE_ON(font))
3951 dump_gdi_font_list();
3953 font_elem_ptr = list_head(&gdi_font_list);
3954 while(font_elem_ptr) {
3955 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3956 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3958 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3959 while(hfontlist_elem_ptr) {
3960 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3961 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3962 if(hflist->hfont == handle) {
3963 list_remove(&hflist->entry);
3964 HeapFree(GetProcessHeap(), 0, hflist);
3965 ret = TRUE;
3968 if(list_empty(&gdiFont->hfontlist)) {
3969 TRACE("Moving to Unused list\n");
3970 list_remove(&gdiFont->entry);
3971 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3976 font_elem_ptr = list_head(&unused_gdi_font_list);
3977 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3978 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3979 while(font_elem_ptr) {
3980 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3981 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3982 TRACE("freeing %p\n", gdiFont);
3983 list_remove(&gdiFont->entry);
3984 free_font(gdiFont);
3986 LeaveCriticalSection( &freetype_cs );
3987 return ret;
3990 /***************************************************
3991 * create_enum_charset_list
3993 * This function creates charset enumeration list because in DEFAULT_CHARSET
3994 * case, the ANSI codepage's charset takes precedence over other charsets.
3995 * This function works as a filter other than DEFAULT_CHARSET case.
3997 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
3999 CHARSETINFO csi;
4000 DWORD n = 0;
4002 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4003 csi.fs.fsCsb[0] != 0) {
4004 list->element[n].mask = csi.fs.fsCsb[0];
4005 list->element[n].charset = csi.ciCharset;
4006 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4007 n++;
4009 else { /* charset is DEFAULT_CHARSET or invalid. */
4010 INT acp, i;
4012 /* Set the current codepage's charset as the first element. */
4013 acp = GetACP();
4014 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4015 csi.fs.fsCsb[0] != 0) {
4016 list->element[n].mask = csi.fs.fsCsb[0];
4017 list->element[n].charset = csi.ciCharset;
4018 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4019 n++;
4022 /* Fill out left elements. */
4023 for (i = 0; i < 32; i++) {
4024 FONTSIGNATURE fs;
4025 fs.fsCsb[0] = 1L << i;
4026 fs.fsCsb[1] = 0;
4027 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4028 continue; /* skip, already added. */
4029 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4030 continue; /* skip, this is an invalid fsCsb bit. */
4032 list->element[n].mask = fs.fsCsb[0];
4033 list->element[n].charset = csi.ciCharset;
4034 list->element[n].name = ElfScriptsW[i];
4035 n++;
4038 list->total = n;
4040 return n;
4043 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4044 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4046 GdiFont *font;
4047 LONG width, height;
4049 if (face->cached_enum_data)
4051 TRACE("Cached\n");
4052 *pelf = face->cached_enum_data->elf;
4053 *pntm = face->cached_enum_data->ntm;
4054 *ptype = face->cached_enum_data->type;
4055 return;
4058 font = alloc_font();
4060 if(face->scalable) {
4061 height = -2048; /* 2048 is the most common em size */
4062 width = 0;
4063 } else {
4064 height = face->size.y_ppem >> 6;
4065 width = face->size.x_ppem >> 6;
4067 font->scale_y = 1.0;
4069 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4071 free_font(font);
4072 return;
4075 font->name = strdupW(face->family->FamilyName);
4076 font->ntmFlags = face->ntmFlags;
4078 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4080 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4082 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4084 lstrcpynW(pelf->elfLogFont.lfFaceName,
4085 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4086 LF_FACESIZE);
4087 lstrcpynW(pelf->elfFullName,
4088 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4089 LF_FULLFACESIZE);
4090 lstrcpynW(pelf->elfStyle,
4091 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4092 LF_FACESIZE);
4094 else
4096 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4098 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4100 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4101 if (face->FullName)
4102 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4103 else
4104 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4105 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4108 pntm->ntmTm.ntmFlags = face->ntmFlags;
4109 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4110 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4111 pntm->ntmFontSig = face->fs;
4113 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4115 pelf->elfLogFont.lfEscapement = 0;
4116 pelf->elfLogFont.lfOrientation = 0;
4117 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4118 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4119 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4120 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4121 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4122 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4123 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4124 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4125 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4126 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4127 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4129 *ptype = 0;
4130 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4131 *ptype |= TRUETYPE_FONTTYPE;
4132 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4133 *ptype |= DEVICE_FONTTYPE;
4134 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4135 *ptype |= RASTER_FONTTYPE;
4137 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4138 if (face->cached_enum_data)
4140 face->cached_enum_data->elf = *pelf;
4141 face->cached_enum_data->ntm = *pntm;
4142 face->cached_enum_data->type = *ptype;
4145 free_font(font);
4148 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4150 struct list *face_elem_ptr;
4152 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4154 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4156 static const WCHAR spaceW[] = { ' ',0 };
4157 WCHAR full_family_name[LF_FULLFACESIZE];
4158 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4160 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4162 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4163 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4164 continue;
4167 strcpyW(full_family_name, family->FamilyName);
4168 strcatW(full_family_name, spaceW);
4169 strcatW(full_family_name, face->StyleName);
4170 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4173 return FALSE;
4176 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4178 static const WCHAR spaceW[] = { ' ',0 };
4179 WCHAR full_family_name[LF_FULLFACESIZE];
4181 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4183 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4185 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4186 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4187 return FALSE;
4190 strcpyW(full_family_name, face->family->FamilyName);
4191 strcatW(full_family_name, spaceW);
4192 strcatW(full_family_name, face->StyleName);
4193 return !strcmpiW(lf->lfFaceName, full_family_name);
4196 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4197 FONTENUMPROCW proc, LPARAM lparam)
4199 ENUMLOGFONTEXW elf;
4200 NEWTEXTMETRICEXW ntm;
4201 DWORD type = 0;
4202 int i;
4204 GetEnumStructs(face, &elf, &ntm, &type);
4205 for(i = 0; i < list->total; i++) {
4206 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4207 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4208 strcpyW(elf.elfScript, OEM_DOSW);
4209 i = 32; /* break out of loop */
4210 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4211 continue;
4212 else {
4213 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4214 if(list->element[i].name)
4215 strcpyW(elf.elfScript, list->element[i].name);
4216 else
4217 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4219 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4220 debugstr_w(elf.elfLogFont.lfFaceName),
4221 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4222 list->element[i].charset, type, debugstr_w(elf.elfScript),
4223 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4224 ntm.ntmTm.ntmFlags);
4225 /* release section before callback (FIXME) */
4226 LeaveCriticalSection( &freetype_cs );
4227 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4228 EnterCriticalSection( &freetype_cs );
4230 return TRUE;
4233 /*************************************************************
4234 * WineEngEnumFonts
4237 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4239 Family *family;
4240 Face *face;
4241 struct list *family_elem_ptr, *face_elem_ptr;
4242 LOGFONTW lf;
4243 struct enum_charset_list enum_charsets;
4245 if (!plf)
4247 lf.lfCharSet = DEFAULT_CHARSET;
4248 lf.lfPitchAndFamily = 0;
4249 lf.lfFaceName[0] = 0;
4250 plf = &lf;
4253 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4255 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4257 GDI_CheckNotLock();
4258 EnterCriticalSection( &freetype_cs );
4259 if(plf->lfFaceName[0]) {
4260 FontSubst *psub;
4261 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4263 if(psub) {
4264 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4265 debugstr_w(psub->to.name));
4266 lf = *plf;
4267 strcpyW(lf.lfFaceName, psub->to.name);
4268 plf = &lf;
4271 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4272 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4273 if(family_matches(family, plf)) {
4274 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4275 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4276 if (!face_matches(face, plf)) continue;
4277 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4281 } else {
4282 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4283 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4284 face_elem_ptr = list_head(&family->faces);
4285 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4286 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4289 LeaveCriticalSection( &freetype_cs );
4290 return 1;
4293 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4295 pt->x.value = vec->x >> 6;
4296 pt->x.fract = (vec->x & 0x3f) << 10;
4297 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4298 pt->y.value = vec->y >> 6;
4299 pt->y.fract = (vec->y & 0x3f) << 10;
4300 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4301 return;
4304 /***************************************************
4305 * According to the MSDN documentation on WideCharToMultiByte,
4306 * certain codepages cannot set the default_used parameter.
4307 * This returns TRUE if the codepage can set that parameter, false else
4308 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4310 static BOOL codepage_sets_default_used(UINT codepage)
4312 switch (codepage)
4314 case CP_UTF7:
4315 case CP_UTF8:
4316 case CP_SYMBOL:
4317 return FALSE;
4318 default:
4319 return TRUE;
4324 * GSUB Table handling functions
4327 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4329 const GSUB_CoverageFormat1* cf1;
4331 cf1 = table;
4333 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4335 int count = GET_BE_WORD(cf1->GlyphCount);
4336 int i;
4337 TRACE("Coverage Format 1, %i glyphs\n",count);
4338 for (i = 0; i < count; i++)
4339 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4340 return i;
4341 return -1;
4343 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4345 const GSUB_CoverageFormat2* cf2;
4346 int i;
4347 int count;
4348 cf2 = (const GSUB_CoverageFormat2*)cf1;
4350 count = GET_BE_WORD(cf2->RangeCount);
4351 TRACE("Coverage Format 2, %i ranges\n",count);
4352 for (i = 0; i < count; i++)
4354 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4355 return -1;
4356 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4357 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4359 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4360 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4363 return -1;
4365 else
4366 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4368 return -1;
4371 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4373 const GSUB_ScriptList *script;
4374 const GSUB_Script *deflt = NULL;
4375 int i;
4376 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4378 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4379 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4381 const GSUB_Script *scr;
4382 int offset;
4384 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4385 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4387 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4388 return scr;
4389 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4390 deflt = scr;
4392 return deflt;
4395 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4397 int i;
4398 int offset;
4399 const GSUB_LangSys *Lang;
4401 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4403 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4405 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4406 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4408 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4409 return Lang;
4411 offset = GET_BE_WORD(script->DefaultLangSys);
4412 if (offset)
4414 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4415 return Lang;
4417 return NULL;
4420 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4422 int i;
4423 const GSUB_FeatureList *feature;
4424 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4426 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4427 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4429 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4430 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4432 const GSUB_Feature *feat;
4433 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4434 return feat;
4437 return NULL;
4440 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4442 int i;
4443 int offset;
4444 const GSUB_LookupList *lookup;
4445 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4447 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4448 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4450 const GSUB_LookupTable *look;
4451 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4452 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4453 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4454 if (GET_BE_WORD(look->LookupType) != 1)
4455 FIXME("We only handle SubType 1\n");
4456 else
4458 int j;
4460 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4462 const GSUB_SingleSubstFormat1 *ssf1;
4463 offset = GET_BE_WORD(look->SubTable[j]);
4464 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4465 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4467 int offset = GET_BE_WORD(ssf1->Coverage);
4468 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4469 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4471 TRACE(" Glyph 0x%x ->",glyph);
4472 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4473 TRACE(" 0x%x\n",glyph);
4476 else
4478 const GSUB_SingleSubstFormat2 *ssf2;
4479 INT index;
4480 INT offset;
4482 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4483 offset = GET_BE_WORD(ssf1->Coverage);
4484 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4485 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4486 TRACE(" Coverage index %i\n",index);
4487 if (index != -1)
4489 TRACE(" Glyph is 0x%x ->",glyph);
4490 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4491 TRACE("0x%x\n",glyph);
4497 return glyph;
4500 static const char* get_opentype_script(const GdiFont *font)
4503 * I am not sure if this is the correct way to generate our script tag
4506 switch (font->charset)
4508 case ANSI_CHARSET: return "latn";
4509 case BALTIC_CHARSET: return "latn"; /* ?? */
4510 case CHINESEBIG5_CHARSET: return "hani";
4511 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4512 case GB2312_CHARSET: return "hani";
4513 case GREEK_CHARSET: return "grek";
4514 case HANGUL_CHARSET: return "hang";
4515 case RUSSIAN_CHARSET: return "cyrl";
4516 case SHIFTJIS_CHARSET: return "kana";
4517 case TURKISH_CHARSET: return "latn"; /* ?? */
4518 case VIETNAMESE_CHARSET: return "latn";
4519 case JOHAB_CHARSET: return "latn"; /* ?? */
4520 case ARABIC_CHARSET: return "arab";
4521 case HEBREW_CHARSET: return "hebr";
4522 case THAI_CHARSET: return "thai";
4523 default: return "latn";
4527 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4529 const GSUB_Header *header;
4530 const GSUB_Script *script;
4531 const GSUB_LangSys *language;
4532 const GSUB_Feature *feature;
4534 if (!font->GSUB_Table)
4535 return glyph;
4537 header = font->GSUB_Table;
4539 script = GSUB_get_script_table(header, get_opentype_script(font));
4540 if (!script)
4542 TRACE("Script not found\n");
4543 return glyph;
4545 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4546 if (!language)
4548 TRACE("Language not found\n");
4549 return glyph;
4551 feature = GSUB_get_feature(header, language, "vrt2");
4552 if (!feature)
4553 feature = GSUB_get_feature(header, language, "vert");
4554 if (!feature)
4556 TRACE("vrt2/vert feature not found\n");
4557 return glyph;
4559 return GSUB_apply_feature(header, feature, glyph);
4562 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4564 FT_UInt glyphId;
4566 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4567 WCHAR wc = (WCHAR)glyph;
4568 BOOL default_used;
4569 BOOL *default_used_pointer;
4570 FT_UInt ret;
4571 char buf;
4572 default_used_pointer = NULL;
4573 default_used = FALSE;
4574 if (codepage_sets_default_used(font->codepage))
4575 default_used_pointer = &default_used;
4576 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4577 ret = 0;
4578 else
4579 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4580 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4581 return get_GSUB_vert_glyph(font,ret);
4584 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4586 if (glyph < 0x100) glyph += 0xf000;
4587 /* there is a number of old pre-Unicode "broken" TTFs, which
4588 do have symbols at U+00XX instead of U+f0XX */
4589 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4590 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4592 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4594 return get_GSUB_vert_glyph(font,glyphId);
4597 /*************************************************************
4598 * WineEngGetGlyphIndices
4601 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4602 LPWORD pgi, DWORD flags)
4604 int i;
4605 WORD default_char;
4606 BOOL got_default = FALSE;
4608 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4610 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4611 got_default = TRUE;
4614 for(i = 0; i < count; i++)
4616 pgi[i] = get_glyph_index(font, lpstr[i]);
4617 if (pgi[i] == 0)
4619 if (!got_default)
4621 if (FT_IS_SFNT(font->ft_face))
4623 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4624 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4626 else
4628 TEXTMETRICW textm;
4629 WineEngGetTextMetrics(font, &textm);
4630 default_char = textm.tmDefaultChar;
4632 got_default = TRUE;
4634 pgi[i] = default_char;
4637 return count;
4640 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4642 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4643 return !memcmp(matrix, &identity, sizeof(FMAT2));
4646 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4648 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4649 return !memcmp(matrix, &identity, sizeof(MAT2));
4652 /*************************************************************
4653 * WineEngGetGlyphOutline
4655 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4656 * except that the first parameter is the HWINEENGFONT of the font in
4657 * question rather than an HDC.
4660 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4661 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4662 const MAT2* lpmat)
4664 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4665 FT_Face ft_face = incoming_font->ft_face;
4666 GdiFont *font = incoming_font;
4667 FT_UInt glyph_index;
4668 DWORD width, height, pitch, needed = 0;
4669 FT_Bitmap ft_bitmap;
4670 FT_Error err;
4671 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4672 FT_Angle angle = 0;
4673 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4674 double widthRatio = 1.0;
4675 FT_Matrix transMat = identityMat;
4676 FT_Matrix transMatUnrotated;
4677 BOOL needsTransform = FALSE;
4678 BOOL tategaki = (font->GSUB_Table != NULL);
4679 UINT original_index;
4681 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4682 buflen, buf, lpmat);
4684 TRACE("font transform %f %f %f %f\n",
4685 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4686 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4688 GDI_CheckNotLock();
4689 EnterCriticalSection( &freetype_cs );
4691 if(format & GGO_GLYPH_INDEX) {
4692 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4693 original_index = glyph;
4694 format &= ~GGO_GLYPH_INDEX;
4695 } else {
4696 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4697 ft_face = font->ft_face;
4698 original_index = glyph_index;
4701 if(format & GGO_UNHINTED) {
4702 load_flags |= FT_LOAD_NO_HINTING;
4703 format &= ~GGO_UNHINTED;
4706 /* tategaki never appears to happen to lower glyph index */
4707 if (glyph_index < TATEGAKI_LOWER_BOUND )
4708 tategaki = FALSE;
4710 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4711 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4712 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4713 font->gmsize * sizeof(GM*));
4714 } else {
4715 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4716 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4718 *lpgm = FONT_GM(font,original_index)->gm;
4719 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4720 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4721 lpgm->gmCellIncX, lpgm->gmCellIncY);
4722 LeaveCriticalSection( &freetype_cs );
4723 return 1; /* FIXME */
4727 if (!font->gm[original_index / GM_BLOCK_SIZE])
4728 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4730 /* Scaling factor */
4731 if (font->aveWidth)
4733 TEXTMETRICW tm;
4735 WineEngGetTextMetrics(font, &tm);
4737 widthRatio = (double)font->aveWidth;
4738 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4740 else
4741 widthRatio = font->scale_y;
4743 /* Scaling transform */
4744 if (widthRatio != 1.0 || font->scale_y != 1.0)
4746 FT_Matrix scaleMat;
4747 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4748 scaleMat.xy = 0;
4749 scaleMat.yx = 0;
4750 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4752 pFT_Matrix_Multiply(&scaleMat, &transMat);
4753 needsTransform = TRUE;
4756 /* Slant transform */
4757 if (font->fake_italic) {
4758 FT_Matrix slantMat;
4760 slantMat.xx = (1 << 16);
4761 slantMat.xy = ((1 << 16) >> 2);
4762 slantMat.yx = 0;
4763 slantMat.yy = (1 << 16);
4764 pFT_Matrix_Multiply(&slantMat, &transMat);
4765 needsTransform = TRUE;
4768 /* Rotation transform */
4769 transMatUnrotated = transMat;
4770 if(font->orientation && !tategaki) {
4771 FT_Matrix rotationMat;
4772 FT_Vector vecAngle;
4773 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4774 pFT_Vector_Unit(&vecAngle, angle);
4775 rotationMat.xx = vecAngle.x;
4776 rotationMat.xy = -vecAngle.y;
4777 rotationMat.yx = -rotationMat.xy;
4778 rotationMat.yy = rotationMat.xx;
4780 pFT_Matrix_Multiply(&rotationMat, &transMat);
4781 needsTransform = TRUE;
4784 /* World transform */
4785 if (!is_identity_FMAT2(&font->font_desc.matrix))
4787 FT_Matrix worldMat;
4788 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4789 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4790 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4791 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4792 pFT_Matrix_Multiply(&worldMat, &transMat);
4793 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4794 needsTransform = TRUE;
4797 /* Extra transformation specified by caller */
4798 if (!is_identity_MAT2(lpmat))
4800 FT_Matrix extraMat;
4801 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4802 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4803 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4804 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4805 pFT_Matrix_Multiply(&extraMat, &transMat);
4806 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4807 needsTransform = TRUE;
4810 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4811 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4812 format == GGO_GRAY8_BITMAP))
4814 load_flags |= FT_LOAD_NO_BITMAP;
4817 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4819 if(err) {
4820 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4821 LeaveCriticalSection( &freetype_cs );
4822 return GDI_ERROR;
4825 if(!needsTransform) {
4826 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4827 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4828 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4830 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4831 bottom = (ft_face->glyph->metrics.horiBearingY -
4832 ft_face->glyph->metrics.height) & -64;
4833 lpgm->gmCellIncX = adv;
4834 lpgm->gmCellIncY = 0;
4835 } else {
4836 INT xc, yc;
4837 FT_Vector vec;
4839 left = right = 0;
4841 for(xc = 0; xc < 2; xc++) {
4842 for(yc = 0; yc < 2; yc++) {
4843 vec.x = (ft_face->glyph->metrics.horiBearingX +
4844 xc * ft_face->glyph->metrics.width);
4845 vec.y = ft_face->glyph->metrics.horiBearingY -
4846 yc * ft_face->glyph->metrics.height;
4847 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4848 pFT_Vector_Transform(&vec, &transMat);
4849 if(xc == 0 && yc == 0) {
4850 left = right = vec.x;
4851 top = bottom = vec.y;
4852 } else {
4853 if(vec.x < left) left = vec.x;
4854 else if(vec.x > right) right = vec.x;
4855 if(vec.y < bottom) bottom = vec.y;
4856 else if(vec.y > top) top = vec.y;
4860 left = left & -64;
4861 right = (right + 63) & -64;
4862 bottom = bottom & -64;
4863 top = (top + 63) & -64;
4865 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4866 vec.x = ft_face->glyph->metrics.horiAdvance;
4867 vec.y = 0;
4868 pFT_Vector_Transform(&vec, &transMat);
4869 lpgm->gmCellIncX = (vec.x+63) >> 6;
4870 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4872 vec.x = ft_face->glyph->metrics.horiAdvance;
4873 vec.y = 0;
4874 pFT_Vector_Transform(&vec, &transMatUnrotated);
4875 adv = (vec.x+63) >> 6;
4878 lsb = left >> 6;
4879 bbx = (right - left) >> 6;
4880 lpgm->gmBlackBoxX = (right - left) >> 6;
4881 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4882 lpgm->gmptGlyphOrigin.x = left >> 6;
4883 lpgm->gmptGlyphOrigin.y = top >> 6;
4885 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4886 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4887 lpgm->gmCellIncX, lpgm->gmCellIncY);
4889 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4890 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4892 FONT_GM(font,original_index)->gm = *lpgm;
4893 FONT_GM(font,original_index)->adv = adv;
4894 FONT_GM(font,original_index)->lsb = lsb;
4895 FONT_GM(font,original_index)->bbx = bbx;
4896 FONT_GM(font,original_index)->init = TRUE;
4899 if(format == GGO_METRICS)
4901 LeaveCriticalSection( &freetype_cs );
4902 return 1; /* FIXME */
4905 if(ft_face->glyph->format != ft_glyph_format_outline &&
4906 (format == GGO_NATIVE || format == GGO_BEZIER ||
4907 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4908 format == GGO_GRAY8_BITMAP))
4910 TRACE("loaded a bitmap\n");
4911 LeaveCriticalSection( &freetype_cs );
4912 return GDI_ERROR;
4915 switch(format) {
4916 case GGO_BITMAP:
4917 width = lpgm->gmBlackBoxX;
4918 height = lpgm->gmBlackBoxY;
4919 pitch = ((width + 31) >> 5) << 2;
4920 needed = pitch * height;
4922 if(!buf || !buflen) break;
4924 switch(ft_face->glyph->format) {
4925 case ft_glyph_format_bitmap:
4927 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4928 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4929 INT h = ft_face->glyph->bitmap.rows;
4930 while(h--) {
4931 memcpy(dst, src, w);
4932 src += ft_face->glyph->bitmap.pitch;
4933 dst += pitch;
4935 break;
4938 case ft_glyph_format_outline:
4939 ft_bitmap.width = width;
4940 ft_bitmap.rows = height;
4941 ft_bitmap.pitch = pitch;
4942 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4943 ft_bitmap.buffer = buf;
4945 if(needsTransform)
4946 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4948 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4950 /* Note: FreeType will only set 'black' bits for us. */
4951 memset(buf, 0, needed);
4952 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4953 break;
4955 default:
4956 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4957 LeaveCriticalSection( &freetype_cs );
4958 return GDI_ERROR;
4960 break;
4962 case GGO_GRAY2_BITMAP:
4963 case GGO_GRAY4_BITMAP:
4964 case GGO_GRAY8_BITMAP:
4965 case WINE_GGO_GRAY16_BITMAP:
4967 unsigned int mult, row, col;
4968 BYTE *start, *ptr;
4970 width = lpgm->gmBlackBoxX;
4971 height = lpgm->gmBlackBoxY;
4972 pitch = (width + 3) / 4 * 4;
4973 needed = pitch * height;
4975 if(!buf || !buflen) break;
4977 switch(ft_face->glyph->format) {
4978 case ft_glyph_format_bitmap:
4980 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4981 INT h = ft_face->glyph->bitmap.rows;
4982 INT x;
4983 memset( buf, 0, needed );
4984 while(h--) {
4985 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4986 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4987 src += ft_face->glyph->bitmap.pitch;
4988 dst += pitch;
4990 LeaveCriticalSection( &freetype_cs );
4991 return needed;
4993 case ft_glyph_format_outline:
4995 ft_bitmap.width = width;
4996 ft_bitmap.rows = height;
4997 ft_bitmap.pitch = pitch;
4998 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4999 ft_bitmap.buffer = buf;
5001 if(needsTransform)
5002 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5004 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5006 memset(ft_bitmap.buffer, 0, buflen);
5008 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5010 if(format == GGO_GRAY2_BITMAP)
5011 mult = 4;
5012 else if(format == GGO_GRAY4_BITMAP)
5013 mult = 16;
5014 else if(format == GGO_GRAY8_BITMAP)
5015 mult = 64;
5016 else /* format == WINE_GGO_GRAY16_BITMAP */
5018 LeaveCriticalSection( &freetype_cs );
5019 return needed;
5021 break;
5023 default:
5024 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5025 LeaveCriticalSection( &freetype_cs );
5026 return GDI_ERROR;
5029 start = buf;
5030 for(row = 0; row < height; row++) {
5031 ptr = start;
5032 for(col = 0; col < width; col++, ptr++) {
5033 *ptr = (((int)*ptr) * mult + 128) / 256;
5035 start += pitch;
5037 break;
5040 case WINE_GGO_HRGB_BITMAP:
5041 case WINE_GGO_HBGR_BITMAP:
5042 case WINE_GGO_VRGB_BITMAP:
5043 case WINE_GGO_VBGR_BITMAP:
5044 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5046 switch (ft_face->glyph->format)
5048 case FT_GLYPH_FORMAT_BITMAP:
5050 BYTE *src, *dst;
5051 INT src_pitch, x;
5053 width = lpgm->gmBlackBoxX;
5054 height = lpgm->gmBlackBoxY;
5055 pitch = width * 4;
5056 needed = pitch * height;
5058 if (!buf || !buflen) break;
5060 memset(buf, 0, buflen);
5061 dst = buf;
5062 src = ft_face->glyph->bitmap.buffer;
5063 src_pitch = ft_face->glyph->bitmap.pitch;
5065 height = min( height, ft_face->glyph->bitmap.rows );
5066 while ( height-- )
5068 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5070 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5071 ((unsigned int *)dst)[x] = ~0u;
5073 src += src_pitch;
5074 dst += pitch;
5077 break;
5080 case FT_GLYPH_FORMAT_OUTLINE:
5082 unsigned int *dst;
5083 BYTE *src;
5084 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5085 INT x_shift, y_shift;
5086 BOOL rgb;
5087 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5088 FT_Render_Mode render_mode =
5089 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5090 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5092 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5094 if ( render_mode == FT_RENDER_MODE_LCD)
5096 lpgm->gmBlackBoxX += 2;
5097 lpgm->gmptGlyphOrigin.x -= 1;
5099 else
5101 lpgm->gmBlackBoxY += 2;
5102 lpgm->gmptGlyphOrigin.y += 1;
5106 width = lpgm->gmBlackBoxX;
5107 height = lpgm->gmBlackBoxY;
5108 pitch = width * 4;
5109 needed = pitch * height;
5111 if (!buf || !buflen) break;
5113 memset(buf, 0, buflen);
5114 dst = buf;
5115 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5117 if ( needsTransform )
5118 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5120 if ( pFT_Library_SetLcdFilter )
5121 pFT_Library_SetLcdFilter( library, lcdfilter );
5122 pFT_Render_Glyph (ft_face->glyph, render_mode);
5124 src = ft_face->glyph->bitmap.buffer;
5125 src_pitch = ft_face->glyph->bitmap.pitch;
5126 src_width = ft_face->glyph->bitmap.width;
5127 src_height = ft_face->glyph->bitmap.rows;
5129 if ( render_mode == FT_RENDER_MODE_LCD)
5131 rgb_interval = 1;
5132 hmul = 3;
5133 vmul = 1;
5135 else
5137 rgb_interval = src_pitch;
5138 hmul = 1;
5139 vmul = 3;
5142 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5143 if ( x_shift < 0 ) x_shift = 0;
5144 if ( x_shift + (src_width / hmul) > width )
5145 x_shift = width - (src_width / hmul);
5147 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5148 if ( y_shift < 0 ) y_shift = 0;
5149 if ( y_shift + (src_height / vmul) > height )
5150 y_shift = height - (src_height / vmul);
5152 dst += x_shift + y_shift * ( pitch / 4 );
5153 while ( src_height )
5155 for ( x = 0; x < src_width / hmul; x++ )
5157 if ( rgb )
5159 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5160 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5161 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5162 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5164 else
5166 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5167 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5168 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5169 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5172 src += src_pitch * vmul;
5173 dst += pitch / 4;
5174 src_height -= vmul;
5177 break;
5180 default:
5181 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5182 LeaveCriticalSection ( &freetype_cs );
5183 return GDI_ERROR;
5186 break;
5188 #else
5189 LeaveCriticalSection( &freetype_cs );
5190 return GDI_ERROR;
5191 #endif
5193 case GGO_NATIVE:
5195 int contour, point = 0, first_pt;
5196 FT_Outline *outline = &ft_face->glyph->outline;
5197 TTPOLYGONHEADER *pph;
5198 TTPOLYCURVE *ppc;
5199 DWORD pph_start, cpfx, type;
5201 if(buflen == 0) buf = NULL;
5203 if (needsTransform && buf) {
5204 pFT_Outline_Transform(outline, &transMat);
5207 for(contour = 0; contour < outline->n_contours; contour++) {
5208 pph_start = needed;
5209 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5210 first_pt = point;
5211 if(buf) {
5212 pph->dwType = TT_POLYGON_TYPE;
5213 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5215 needed += sizeof(*pph);
5216 point++;
5217 while(point <= outline->contours[contour]) {
5218 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5219 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5220 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5221 cpfx = 0;
5222 do {
5223 if(buf)
5224 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5225 cpfx++;
5226 point++;
5227 } while(point <= outline->contours[contour] &&
5228 (outline->tags[point] & FT_Curve_Tag_On) ==
5229 (outline->tags[point-1] & FT_Curve_Tag_On));
5230 /* At the end of a contour Windows adds the start point, but
5231 only for Beziers */
5232 if(point > outline->contours[contour] &&
5233 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5234 if(buf)
5235 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5236 cpfx++;
5237 } else if(point <= outline->contours[contour] &&
5238 outline->tags[point] & FT_Curve_Tag_On) {
5239 /* add closing pt for bezier */
5240 if(buf)
5241 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5242 cpfx++;
5243 point++;
5245 if(buf) {
5246 ppc->wType = type;
5247 ppc->cpfx = cpfx;
5249 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5251 if(buf)
5252 pph->cb = needed - pph_start;
5254 break;
5256 case GGO_BEZIER:
5258 /* Convert the quadratic Beziers to cubic Beziers.
5259 The parametric eqn for a cubic Bezier is, from PLRM:
5260 r(t) = at^3 + bt^2 + ct + r0
5261 with the control points:
5262 r1 = r0 + c/3
5263 r2 = r1 + (c + b)/3
5264 r3 = r0 + c + b + a
5266 A quadratic Bezier has the form:
5267 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5269 So equating powers of t leads to:
5270 r1 = 2/3 p1 + 1/3 p0
5271 r2 = 2/3 p1 + 1/3 p2
5272 and of course r0 = p0, r3 = p2
5275 int contour, point = 0, first_pt;
5276 FT_Outline *outline = &ft_face->glyph->outline;
5277 TTPOLYGONHEADER *pph;
5278 TTPOLYCURVE *ppc;
5279 DWORD pph_start, cpfx, type;
5280 FT_Vector cubic_control[4];
5281 if(buflen == 0) buf = NULL;
5283 if (needsTransform && buf) {
5284 pFT_Outline_Transform(outline, &transMat);
5287 for(contour = 0; contour < outline->n_contours; contour++) {
5288 pph_start = needed;
5289 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5290 first_pt = point;
5291 if(buf) {
5292 pph->dwType = TT_POLYGON_TYPE;
5293 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5295 needed += sizeof(*pph);
5296 point++;
5297 while(point <= outline->contours[contour]) {
5298 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5299 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5300 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5301 cpfx = 0;
5302 do {
5303 if(type == TT_PRIM_LINE) {
5304 if(buf)
5305 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5306 cpfx++;
5307 point++;
5308 } else {
5309 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5310 so cpfx = 3n */
5312 /* FIXME: Possible optimization in endpoint calculation
5313 if there are two consecutive curves */
5314 cubic_control[0] = outline->points[point-1];
5315 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5316 cubic_control[0].x += outline->points[point].x + 1;
5317 cubic_control[0].y += outline->points[point].y + 1;
5318 cubic_control[0].x >>= 1;
5319 cubic_control[0].y >>= 1;
5321 if(point+1 > outline->contours[contour])
5322 cubic_control[3] = outline->points[first_pt];
5323 else {
5324 cubic_control[3] = outline->points[point+1];
5325 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5326 cubic_control[3].x += outline->points[point].x + 1;
5327 cubic_control[3].y += outline->points[point].y + 1;
5328 cubic_control[3].x >>= 1;
5329 cubic_control[3].y >>= 1;
5332 /* r1 = 1/3 p0 + 2/3 p1
5333 r2 = 1/3 p2 + 2/3 p1 */
5334 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5335 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5336 cubic_control[2] = cubic_control[1];
5337 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5338 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5339 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5340 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5341 if(buf) {
5342 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5343 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5344 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5346 cpfx += 3;
5347 point++;
5349 } while(point <= outline->contours[contour] &&
5350 (outline->tags[point] & FT_Curve_Tag_On) ==
5351 (outline->tags[point-1] & FT_Curve_Tag_On));
5352 /* At the end of a contour Windows adds the start point,
5353 but only for Beziers and we've already done that.
5355 if(point <= outline->contours[contour] &&
5356 outline->tags[point] & FT_Curve_Tag_On) {
5357 /* This is the closing pt of a bezier, but we've already
5358 added it, so just inc point and carry on */
5359 point++;
5361 if(buf) {
5362 ppc->wType = type;
5363 ppc->cpfx = cpfx;
5365 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5367 if(buf)
5368 pph->cb = needed - pph_start;
5370 break;
5373 default:
5374 FIXME("Unsupported format %d\n", format);
5375 LeaveCriticalSection( &freetype_cs );
5376 return GDI_ERROR;
5378 LeaveCriticalSection( &freetype_cs );
5379 return needed;
5382 static BOOL get_bitmap_text_metrics(GdiFont *font)
5384 FT_Face ft_face = font->ft_face;
5385 #ifdef HAVE_FREETYPE_FTWINFNT_H
5386 FT_WinFNT_HeaderRec winfnt_header;
5387 #endif
5388 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5389 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5390 font->potm->otmSize = size;
5392 #define TM font->potm->otmTextMetrics
5393 #ifdef HAVE_FREETYPE_FTWINFNT_H
5394 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5396 TM.tmHeight = winfnt_header.pixel_height;
5397 TM.tmAscent = winfnt_header.ascent;
5398 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5399 TM.tmInternalLeading = winfnt_header.internal_leading;
5400 TM.tmExternalLeading = winfnt_header.external_leading;
5401 TM.tmAveCharWidth = winfnt_header.avg_width;
5402 TM.tmMaxCharWidth = winfnt_header.max_width;
5403 TM.tmWeight = winfnt_header.weight;
5404 TM.tmOverhang = 0;
5405 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5406 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5407 TM.tmFirstChar = winfnt_header.first_char;
5408 TM.tmLastChar = winfnt_header.last_char;
5409 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5410 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5411 TM.tmItalic = winfnt_header.italic;
5412 TM.tmUnderlined = font->underline;
5413 TM.tmStruckOut = font->strikeout;
5414 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5415 TM.tmCharSet = winfnt_header.charset;
5417 else
5418 #endif
5420 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5421 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5422 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5423 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5424 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5425 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5426 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5427 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5428 TM.tmOverhang = 0;
5429 TM.tmDigitizedAspectX = 96; /* FIXME */
5430 TM.tmDigitizedAspectY = 96; /* FIXME */
5431 TM.tmFirstChar = 1;
5432 TM.tmLastChar = 255;
5433 TM.tmDefaultChar = 32;
5434 TM.tmBreakChar = 32;
5435 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5436 TM.tmUnderlined = font->underline;
5437 TM.tmStruckOut = font->strikeout;
5438 /* NB inverted meaning of TMPF_FIXED_PITCH */
5439 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5440 TM.tmCharSet = font->charset;
5442 #undef TM
5444 return TRUE;
5448 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5450 double scale_x, scale_y;
5452 if (font->aveWidth)
5454 scale_x = (double)font->aveWidth;
5455 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5457 else
5458 scale_x = font->scale_y;
5460 scale_x *= fabs(font->font_desc.matrix.eM11);
5461 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5463 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5464 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5466 SCALE_Y(ptm->tmHeight);
5467 SCALE_Y(ptm->tmAscent);
5468 SCALE_Y(ptm->tmDescent);
5469 SCALE_Y(ptm->tmInternalLeading);
5470 SCALE_Y(ptm->tmExternalLeading);
5471 SCALE_Y(ptm->tmOverhang);
5473 SCALE_X(ptm->tmAveCharWidth);
5474 SCALE_X(ptm->tmMaxCharWidth);
5476 #undef SCALE_X
5477 #undef SCALE_Y
5480 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5482 double scale_x, scale_y;
5484 if (font->aveWidth)
5486 scale_x = (double)font->aveWidth;
5487 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5489 else
5490 scale_x = font->scale_y;
5492 scale_x *= fabs(font->font_desc.matrix.eM11);
5493 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5495 scale_font_metrics(font, &potm->otmTextMetrics);
5497 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5498 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5500 SCALE_Y(potm->otmAscent);
5501 SCALE_Y(potm->otmDescent);
5502 SCALE_Y(potm->otmLineGap);
5503 SCALE_Y(potm->otmsCapEmHeight);
5504 SCALE_Y(potm->otmsXHeight);
5505 SCALE_Y(potm->otmrcFontBox.top);
5506 SCALE_Y(potm->otmrcFontBox.bottom);
5507 SCALE_X(potm->otmrcFontBox.left);
5508 SCALE_X(potm->otmrcFontBox.right);
5509 SCALE_Y(potm->otmMacAscent);
5510 SCALE_Y(potm->otmMacDescent);
5511 SCALE_Y(potm->otmMacLineGap);
5512 SCALE_X(potm->otmptSubscriptSize.x);
5513 SCALE_Y(potm->otmptSubscriptSize.y);
5514 SCALE_X(potm->otmptSubscriptOffset.x);
5515 SCALE_Y(potm->otmptSubscriptOffset.y);
5516 SCALE_X(potm->otmptSuperscriptSize.x);
5517 SCALE_Y(potm->otmptSuperscriptSize.y);
5518 SCALE_X(potm->otmptSuperscriptOffset.x);
5519 SCALE_Y(potm->otmptSuperscriptOffset.y);
5520 SCALE_Y(potm->otmsStrikeoutSize);
5521 SCALE_Y(potm->otmsStrikeoutPosition);
5522 SCALE_Y(potm->otmsUnderscoreSize);
5523 SCALE_Y(potm->otmsUnderscorePosition);
5525 #undef SCALE_X
5526 #undef SCALE_Y
5529 /*************************************************************
5530 * WineEngGetTextMetrics
5533 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5535 GDI_CheckNotLock();
5536 EnterCriticalSection( &freetype_cs );
5537 if(!font->potm) {
5538 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5539 if(!get_bitmap_text_metrics(font))
5541 LeaveCriticalSection( &freetype_cs );
5542 return FALSE;
5545 /* Make sure that the font has sane width/height ratio */
5546 if (font->aveWidth)
5548 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5550 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5551 font->aveWidth = 0;
5556 *ptm = font->potm->otmTextMetrics;
5557 scale_font_metrics(font, ptm);
5558 LeaveCriticalSection( &freetype_cs );
5559 return TRUE;
5562 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5564 int i;
5566 for(i = 0; i < ft_face->num_charmaps; i++)
5568 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5569 return TRUE;
5571 return FALSE;
5574 /*************************************************************
5575 * WineEngGetOutlineTextMetrics
5578 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5579 OUTLINETEXTMETRICW *potm)
5581 FT_Face ft_face = font->ft_face;
5582 UINT needed, lenfam, lensty, ret;
5583 TT_OS2 *pOS2;
5584 TT_HoriHeader *pHori;
5585 TT_Postscript *pPost;
5586 FT_Fixed x_scale, y_scale;
5587 WCHAR *family_nameW, *style_nameW;
5588 static const WCHAR spaceW[] = {' ', '\0'};
5589 char *cp;
5590 INT ascent, descent;
5592 TRACE("font=%p\n", font);
5594 if(!FT_IS_SCALABLE(ft_face))
5595 return 0;
5597 GDI_CheckNotLock();
5598 EnterCriticalSection( &freetype_cs );
5600 if(font->potm) {
5601 if(cbSize >= font->potm->otmSize)
5603 memcpy(potm, font->potm, font->potm->otmSize);
5604 scale_outline_font_metrics(font, potm);
5606 LeaveCriticalSection( &freetype_cs );
5607 return font->potm->otmSize;
5611 needed = sizeof(*potm);
5613 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5614 family_nameW = strdupW(font->name);
5616 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5617 * sizeof(WCHAR);
5618 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5619 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5620 style_nameW, lensty/sizeof(WCHAR));
5622 /* These names should be read from the TT name table */
5624 /* length of otmpFamilyName */
5625 needed += lenfam;
5627 /* length of otmpFaceName */
5628 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5629 needed += lenfam; /* just the family name */
5630 } else {
5631 needed += lenfam + lensty; /* family + " " + style */
5634 /* length of otmpStyleName */
5635 needed += lensty;
5637 /* length of otmpFullName */
5638 needed += lenfam + lensty;
5641 x_scale = ft_face->size->metrics.x_scale;
5642 y_scale = ft_face->size->metrics.y_scale;
5644 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5645 if(!pOS2) {
5646 FIXME("Can't find OS/2 table - not TT font?\n");
5647 ret = 0;
5648 goto end;
5651 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5652 if(!pHori) {
5653 FIXME("Can't find HHEA table - not TT font?\n");
5654 ret = 0;
5655 goto end;
5658 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5660 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",
5661 pOS2->usWinAscent, pOS2->usWinDescent,
5662 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5663 ft_face->ascender, ft_face->descender, ft_face->height,
5664 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5665 ft_face->bbox.yMax, ft_face->bbox.yMin);
5667 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5668 font->potm->otmSize = needed;
5670 #define TM font->potm->otmTextMetrics
5672 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5673 ascent = pHori->Ascender;
5674 descent = -pHori->Descender;
5675 } else {
5676 ascent = pOS2->usWinAscent;
5677 descent = pOS2->usWinDescent;
5680 if(font->yMax) {
5681 TM.tmAscent = font->yMax;
5682 TM.tmDescent = -font->yMin;
5683 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5684 } else {
5685 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5686 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5687 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5688 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5691 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5693 /* MSDN says:
5694 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5696 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5697 ((ascent + descent) -
5698 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5700 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5701 if (TM.tmAveCharWidth == 0) {
5702 TM.tmAveCharWidth = 1;
5704 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5705 TM.tmWeight = FW_REGULAR;
5706 if (font->fake_bold)
5707 TM.tmWeight = FW_BOLD;
5708 else
5710 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5712 if (pOS2->usWeightClass > FW_MEDIUM)
5713 TM.tmWeight = pOS2->usWeightClass;
5715 else if (pOS2->usWeightClass <= FW_MEDIUM)
5716 TM.tmWeight = pOS2->usWeightClass;
5718 TM.tmOverhang = 0;
5719 TM.tmDigitizedAspectX = 300;
5720 TM.tmDigitizedAspectY = 300;
5721 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5722 * symbol range to 0 - f0ff
5725 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5727 TM.tmFirstChar = 0;
5728 switch(GetACP())
5730 case 1257: /* Baltic */
5731 TM.tmLastChar = 0xf8fd;
5732 break;
5733 default:
5734 TM.tmLastChar = 0xf0ff;
5736 TM.tmBreakChar = 0x20;
5737 TM.tmDefaultChar = 0x1f;
5739 else
5741 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5742 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5744 if(pOS2->usFirstCharIndex <= 1)
5745 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5746 else if (pOS2->usFirstCharIndex > 0xff)
5747 TM.tmBreakChar = 0x20;
5748 else
5749 TM.tmBreakChar = pOS2->usFirstCharIndex;
5750 TM.tmDefaultChar = TM.tmBreakChar - 1;
5752 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5753 TM.tmUnderlined = font->underline;
5754 TM.tmStruckOut = font->strikeout;
5756 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5757 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5758 (pOS2->version == 0xFFFFU ||
5759 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5760 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5761 else
5762 TM.tmPitchAndFamily = 0;
5764 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5766 case PAN_FAMILY_SCRIPT:
5767 TM.tmPitchAndFamily |= FF_SCRIPT;
5768 break;
5770 case PAN_FAMILY_DECORATIVE:
5771 TM.tmPitchAndFamily |= FF_DECORATIVE;
5772 break;
5774 case PAN_ANY:
5775 case PAN_NO_FIT:
5776 case PAN_FAMILY_TEXT_DISPLAY:
5777 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5778 /* which is clearly not what the panose spec says. */
5779 default:
5780 if(TM.tmPitchAndFamily == 0 || /* fixed */
5781 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5782 TM.tmPitchAndFamily = FF_MODERN;
5783 else
5785 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5787 case PAN_ANY:
5788 case PAN_NO_FIT:
5789 default:
5790 TM.tmPitchAndFamily |= FF_DONTCARE;
5791 break;
5793 case PAN_SERIF_COVE:
5794 case PAN_SERIF_OBTUSE_COVE:
5795 case PAN_SERIF_SQUARE_COVE:
5796 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5797 case PAN_SERIF_SQUARE:
5798 case PAN_SERIF_THIN:
5799 case PAN_SERIF_BONE:
5800 case PAN_SERIF_EXAGGERATED:
5801 case PAN_SERIF_TRIANGLE:
5802 TM.tmPitchAndFamily |= FF_ROMAN;
5803 break;
5805 case PAN_SERIF_NORMAL_SANS:
5806 case PAN_SERIF_OBTUSE_SANS:
5807 case PAN_SERIF_PERP_SANS:
5808 case PAN_SERIF_FLARED:
5809 case PAN_SERIF_ROUNDED:
5810 TM.tmPitchAndFamily |= FF_SWISS;
5811 break;
5814 break;
5817 if(FT_IS_SCALABLE(ft_face))
5818 TM.tmPitchAndFamily |= TMPF_VECTOR;
5820 if(FT_IS_SFNT(ft_face))
5822 if (font->ntmFlags & NTM_PS_OPENTYPE)
5823 TM.tmPitchAndFamily |= TMPF_DEVICE;
5824 else
5825 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5828 TM.tmCharSet = font->charset;
5830 font->potm->otmFiller = 0;
5831 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5832 font->potm->otmfsSelection = pOS2->fsSelection;
5833 font->potm->otmfsType = pOS2->fsType;
5834 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5835 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5836 font->potm->otmItalicAngle = 0; /* POST table */
5837 font->potm->otmEMSquare = ft_face->units_per_EM;
5838 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5839 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5840 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5841 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5842 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5843 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5844 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5845 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5846 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5847 font->potm->otmMacAscent = TM.tmAscent;
5848 font->potm->otmMacDescent = -TM.tmDescent;
5849 font->potm->otmMacLineGap = font->potm->otmLineGap;
5850 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5851 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5852 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5853 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5854 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5855 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5856 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5857 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5858 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5859 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5860 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5861 if(!pPost) {
5862 font->potm->otmsUnderscoreSize = 0;
5863 font->potm->otmsUnderscorePosition = 0;
5864 } else {
5865 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5866 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5868 #undef TM
5870 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5871 cp = (char*)font->potm + sizeof(*font->potm);
5872 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5873 strcpyW((WCHAR*)cp, family_nameW);
5874 cp += lenfam;
5875 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5876 strcpyW((WCHAR*)cp, style_nameW);
5877 cp += lensty;
5878 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5879 strcpyW((WCHAR*)cp, family_nameW);
5880 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5881 strcatW((WCHAR*)cp, spaceW);
5882 strcatW((WCHAR*)cp, style_nameW);
5883 cp += lenfam + lensty;
5884 } else
5885 cp += lenfam;
5886 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5887 strcpyW((WCHAR*)cp, family_nameW);
5888 strcatW((WCHAR*)cp, spaceW);
5889 strcatW((WCHAR*)cp, style_nameW);
5890 ret = needed;
5892 if(potm && needed <= cbSize)
5894 memcpy(potm, font->potm, font->potm->otmSize);
5895 scale_outline_font_metrics(font, potm);
5898 end:
5899 HeapFree(GetProcessHeap(), 0, style_nameW);
5900 HeapFree(GetProcessHeap(), 0, family_nameW);
5902 LeaveCriticalSection( &freetype_cs );
5903 return ret;
5906 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5908 HFONTLIST *hfontlist;
5909 child->font = alloc_font();
5910 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5911 if(!child->font->ft_face)
5913 free_font(child->font);
5914 child->font = NULL;
5915 return FALSE;
5918 child->font->font_desc = font->font_desc;
5919 child->font->ntmFlags = child->face->ntmFlags;
5920 child->font->orientation = font->orientation;
5921 child->font->scale_y = font->scale_y;
5922 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5923 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5924 child->font->name = strdupW(child->face->family->FamilyName);
5925 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5926 child->font->base_font = font;
5927 list_add_head(&child_font_list, &child->font->entry);
5928 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5929 return TRUE;
5932 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5934 FT_UInt g;
5935 CHILD_FONT *child_font;
5937 if(font->base_font)
5938 font = font->base_font;
5940 *linked_font = font;
5942 if((*glyph = get_glyph_index(font, c)))
5943 return TRUE;
5945 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5947 if(!child_font->font)
5948 if(!load_child_font(font, child_font))
5949 continue;
5951 if(!child_font->font->ft_face)
5952 continue;
5953 g = get_glyph_index(child_font->font, c);
5954 if(g)
5956 *glyph = g;
5957 *linked_font = child_font->font;
5958 return TRUE;
5961 return FALSE;
5964 /*************************************************************
5965 * WineEngGetCharWidth
5968 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5969 LPINT buffer)
5971 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5972 UINT c;
5973 GLYPHMETRICS gm;
5974 FT_UInt glyph_index;
5975 GdiFont *linked_font;
5977 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5979 GDI_CheckNotLock();
5980 EnterCriticalSection( &freetype_cs );
5981 for(c = firstChar; c <= lastChar; c++) {
5982 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5983 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5984 &gm, 0, NULL, &identity);
5985 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5987 LeaveCriticalSection( &freetype_cs );
5988 return TRUE;
5991 /*************************************************************
5992 * WineEngGetCharABCWidths
5995 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5996 LPABC buffer)
5998 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5999 UINT c;
6000 GLYPHMETRICS gm;
6001 FT_UInt glyph_index;
6002 GdiFont *linked_font;
6004 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6006 if(!FT_IS_SCALABLE(font->ft_face))
6007 return FALSE;
6009 GDI_CheckNotLock();
6010 EnterCriticalSection( &freetype_cs );
6012 for(c = firstChar; c <= lastChar; c++) {
6013 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6014 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6015 &gm, 0, NULL, &identity);
6016 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6017 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6018 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6019 FONT_GM(linked_font,glyph_index)->bbx;
6021 LeaveCriticalSection( &freetype_cs );
6022 return TRUE;
6025 /*************************************************************
6026 * WineEngGetCharABCWidthsFloat
6029 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6031 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6032 UINT c;
6033 GLYPHMETRICS gm;
6034 FT_UInt glyph_index;
6035 GdiFont *linked_font;
6037 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6039 GDI_CheckNotLock();
6040 EnterCriticalSection( &freetype_cs );
6042 for (c = first; c <= last; c++)
6044 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6045 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6046 &gm, 0, NULL, &identity);
6047 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6048 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6049 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6050 FONT_GM(linked_font, glyph_index)->lsb -
6051 FONT_GM(linked_font, glyph_index)->bbx;
6053 LeaveCriticalSection( &freetype_cs );
6054 return TRUE;
6057 /*************************************************************
6058 * WineEngGetCharABCWidthsI
6061 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6062 LPABC buffer)
6064 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6065 UINT c;
6066 GLYPHMETRICS gm;
6067 FT_UInt glyph_index;
6068 GdiFont *linked_font;
6070 if(!FT_HAS_HORIZONTAL(font->ft_face))
6071 return FALSE;
6073 GDI_CheckNotLock();
6074 EnterCriticalSection( &freetype_cs );
6076 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6077 if (!pgi)
6078 for(c = firstChar; c < firstChar+count; c++) {
6079 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6080 &gm, 0, NULL, &identity);
6081 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6082 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6083 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6084 - FONT_GM(linked_font,c)->bbx;
6086 else
6087 for(c = 0; c < count; c++) {
6088 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6089 &gm, 0, NULL, &identity);
6090 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6091 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6092 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6093 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6096 LeaveCriticalSection( &freetype_cs );
6097 return TRUE;
6100 /*************************************************************
6101 * WineEngGetTextExtentExPoint
6104 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6105 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6107 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6108 INT idx;
6109 INT nfit = 0, ext;
6110 GLYPHMETRICS gm;
6111 TEXTMETRICW tm;
6112 FT_UInt glyph_index;
6113 GdiFont *linked_font;
6115 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6116 max_ext, size);
6118 GDI_CheckNotLock();
6119 EnterCriticalSection( &freetype_cs );
6121 size->cx = 0;
6122 WineEngGetTextMetrics(font, &tm);
6123 size->cy = tm.tmHeight;
6125 for(idx = 0; idx < count; idx++) {
6126 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6127 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6128 &gm, 0, NULL, &identity);
6129 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6130 ext = size->cx;
6131 if (! pnfit || ext <= max_ext) {
6132 ++nfit;
6133 if (dxs)
6134 dxs[idx] = ext;
6138 if (pnfit)
6139 *pnfit = nfit;
6141 LeaveCriticalSection( &freetype_cs );
6142 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6143 return TRUE;
6146 /*************************************************************
6147 * WineEngGetTextExtentExPointI
6150 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6151 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6153 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6154 INT idx;
6155 INT nfit = 0, ext;
6156 GLYPHMETRICS gm;
6157 TEXTMETRICW tm;
6159 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6161 GDI_CheckNotLock();
6162 EnterCriticalSection( &freetype_cs );
6164 size->cx = 0;
6165 WineEngGetTextMetrics(font, &tm);
6166 size->cy = tm.tmHeight;
6168 for(idx = 0; idx < count; idx++) {
6169 WineEngGetGlyphOutline(font, indices[idx],
6170 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6171 &identity);
6172 size->cx += FONT_GM(font,indices[idx])->adv;
6173 ext = size->cx;
6174 if (! pnfit || ext <= max_ext) {
6175 ++nfit;
6176 if (dxs)
6177 dxs[idx] = ext;
6181 if (pnfit)
6182 *pnfit = nfit;
6184 LeaveCriticalSection( &freetype_cs );
6185 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6186 return TRUE;
6189 /*************************************************************
6190 * WineEngGetFontData
6193 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6194 DWORD cbData)
6196 FT_Face ft_face = font->ft_face;
6197 FT_ULong len;
6198 FT_Error err;
6200 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6201 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6202 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6204 if(!FT_IS_SFNT(ft_face))
6205 return GDI_ERROR;
6207 if(!buf)
6208 len = 0;
6209 else
6210 len = cbData;
6212 if(table) { /* MS tags differ in endianness from FT ones */
6213 table = table >> 24 | table << 24 |
6214 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6217 /* make sure value of len is the value freetype says it needs */
6218 if(buf && len)
6220 FT_ULong needed = 0;
6221 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6222 if( !err && needed < len) len = needed;
6224 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6226 if(err) {
6227 TRACE("Can't find table %c%c%c%c\n",
6228 /* bytes were reversed */
6229 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6230 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6231 return GDI_ERROR;
6233 return len;
6236 /*************************************************************
6237 * WineEngGetTextFace
6240 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6242 INT n = strlenW(font->name) + 1;
6243 if(str) {
6244 lstrcpynW(str, font->name, count);
6245 return min(count, n);
6246 } else
6247 return n;
6250 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6252 if (fs) *fs = font->fs;
6253 return font->charset;
6256 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6258 GdiFont *font = dc->gdiFont, *linked_font;
6259 struct list *first_hfont;
6260 BOOL ret;
6262 GDI_CheckNotLock();
6263 EnterCriticalSection( &freetype_cs );
6264 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6265 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6266 if(font == linked_font)
6267 *new_hfont = dc->hFont;
6268 else
6270 first_hfont = list_head(&linked_font->hfontlist);
6271 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6273 LeaveCriticalSection( &freetype_cs );
6274 return ret;
6277 /* Retrieve a list of supported Unicode ranges for a given font.
6278 * Can be called with NULL gs to calculate the buffer size. Returns
6279 * the number of ranges found.
6281 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6283 DWORD num_ranges = 0;
6285 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6287 FT_UInt glyph_code;
6288 FT_ULong char_code, char_code_prev;
6290 glyph_code = 0;
6291 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6293 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6294 face->num_glyphs, glyph_code, char_code);
6296 if (!glyph_code) return 0;
6298 if (gs)
6300 gs->ranges[0].wcLow = (USHORT)char_code;
6301 gs->ranges[0].cGlyphs = 0;
6302 gs->cGlyphsSupported = 0;
6305 num_ranges = 1;
6306 while (glyph_code)
6308 if (char_code < char_code_prev)
6310 ERR("expected increasing char code from FT_Get_Next_Char\n");
6311 return 0;
6313 if (char_code - char_code_prev > 1)
6315 num_ranges++;
6316 if (gs)
6318 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6319 gs->ranges[num_ranges - 1].cGlyphs = 1;
6320 gs->cGlyphsSupported++;
6323 else if (gs)
6325 gs->ranges[num_ranges - 1].cGlyphs++;
6326 gs->cGlyphsSupported++;
6328 char_code_prev = char_code;
6329 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6332 else
6333 FIXME("encoding %u not supported\n", face->charmap->encoding);
6335 return num_ranges;
6338 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6340 DWORD size = 0;
6341 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6343 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6344 if (glyphset)
6346 glyphset->cbThis = size;
6347 glyphset->cRanges = num_ranges;
6348 glyphset->flAccel = 0;
6350 return size;
6353 /*************************************************************
6354 * FontIsLinked
6356 BOOL WineEngFontIsLinked(GdiFont *font)
6358 BOOL ret;
6359 GDI_CheckNotLock();
6360 EnterCriticalSection( &freetype_cs );
6361 ret = !list_empty(&font->child_fonts);
6362 LeaveCriticalSection( &freetype_cs );
6363 return ret;
6366 static BOOL is_hinting_enabled(void)
6368 /* Use the >= 2.2.0 function if available */
6369 if(pFT_Get_TrueType_Engine_Type)
6371 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6372 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6374 #ifdef FT_DRIVER_HAS_HINTER
6375 else
6377 FT_Module mod;
6379 /* otherwise if we've been compiled with < 2.2.0 headers
6380 use the internal macro */
6381 mod = pFT_Get_Module(library, "truetype");
6382 if(mod && FT_DRIVER_HAS_HINTER(mod))
6383 return TRUE;
6385 #endif
6387 return FALSE;
6390 static BOOL is_subpixel_rendering_enabled( void )
6392 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6393 return pFT_Library_SetLcdFilter &&
6394 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6395 #else
6396 return FALSE;
6397 #endif
6400 /*************************************************************************
6401 * GetRasterizerCaps (GDI32.@)
6403 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6405 static int hinting = -1;
6406 static int subpixel = -1;
6408 if(hinting == -1)
6410 hinting = is_hinting_enabled();
6411 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6414 if ( subpixel == -1 )
6416 subpixel = is_subpixel_rendering_enabled();
6417 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6420 lprs->nSize = sizeof(RASTERIZER_STATUS);
6421 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6422 if ( subpixel )
6423 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6424 lprs->nLanguageID = 0;
6425 return TRUE;
6428 /*************************************************************
6429 * WineEngRealizationInfo
6431 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6433 FIXME("(%p, %p): stub!\n", font, info);
6435 info->flags = 1;
6436 if(FT_IS_SCALABLE(font->ft_face))
6437 info->flags |= 2;
6439 info->cache_num = font->cache_num;
6440 info->unknown2 = -1;
6441 return TRUE;
6444 /*************************************************************************
6445 * Kerning support for TrueType fonts
6447 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6449 struct TT_kern_table
6451 USHORT version;
6452 USHORT nTables;
6455 struct TT_kern_subtable
6457 USHORT version;
6458 USHORT length;
6459 union
6461 USHORT word;
6462 struct
6464 USHORT horizontal : 1;
6465 USHORT minimum : 1;
6466 USHORT cross_stream: 1;
6467 USHORT override : 1;
6468 USHORT reserved1 : 4;
6469 USHORT format : 8;
6470 } bits;
6471 } coverage;
6474 struct TT_format0_kern_subtable
6476 USHORT nPairs;
6477 USHORT searchRange;
6478 USHORT entrySelector;
6479 USHORT rangeShift;
6482 struct TT_kern_pair
6484 USHORT left;
6485 USHORT right;
6486 short value;
6489 static DWORD parse_format0_kern_subtable(GdiFont *font,
6490 const struct TT_format0_kern_subtable *tt_f0_ks,
6491 const USHORT *glyph_to_char,
6492 KERNINGPAIR *kern_pair, DWORD cPairs)
6494 USHORT i, nPairs;
6495 const struct TT_kern_pair *tt_kern_pair;
6497 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6499 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6501 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6502 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6503 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6505 if (!kern_pair || !cPairs)
6506 return nPairs;
6508 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6510 nPairs = min(nPairs, cPairs);
6512 for (i = 0; i < nPairs; i++)
6514 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6515 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6516 /* this algorithm appears to better match what Windows does */
6517 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6518 if (kern_pair->iKernAmount < 0)
6520 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6521 kern_pair->iKernAmount -= font->ppem;
6523 else if (kern_pair->iKernAmount > 0)
6525 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6526 kern_pair->iKernAmount += font->ppem;
6528 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6530 TRACE("left %u right %u value %d\n",
6531 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6533 kern_pair++;
6535 TRACE("copied %u entries\n", nPairs);
6536 return nPairs;
6539 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6541 DWORD length;
6542 void *buf;
6543 const struct TT_kern_table *tt_kern_table;
6544 const struct TT_kern_subtable *tt_kern_subtable;
6545 USHORT i, nTables;
6546 USHORT *glyph_to_char;
6548 GDI_CheckNotLock();
6549 EnterCriticalSection( &freetype_cs );
6550 if (font->total_kern_pairs != (DWORD)-1)
6552 if (cPairs && kern_pair)
6554 cPairs = min(cPairs, font->total_kern_pairs);
6555 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6556 LeaveCriticalSection( &freetype_cs );
6557 return cPairs;
6559 LeaveCriticalSection( &freetype_cs );
6560 return font->total_kern_pairs;
6563 font->total_kern_pairs = 0;
6565 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6567 if (length == GDI_ERROR)
6569 TRACE("no kerning data in the font\n");
6570 LeaveCriticalSection( &freetype_cs );
6571 return 0;
6574 buf = HeapAlloc(GetProcessHeap(), 0, length);
6575 if (!buf)
6577 WARN("Out of memory\n");
6578 LeaveCriticalSection( &freetype_cs );
6579 return 0;
6582 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6584 /* build a glyph index to char code map */
6585 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6586 if (!glyph_to_char)
6588 WARN("Out of memory allocating a glyph index to char code map\n");
6589 HeapFree(GetProcessHeap(), 0, buf);
6590 LeaveCriticalSection( &freetype_cs );
6591 return 0;
6594 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6596 FT_UInt glyph_code;
6597 FT_ULong char_code;
6599 glyph_code = 0;
6600 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6602 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6603 font->ft_face->num_glyphs, glyph_code, char_code);
6605 while (glyph_code)
6607 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6609 /* FIXME: This doesn't match what Windows does: it does some fancy
6610 * things with duplicate glyph index to char code mappings, while
6611 * we just avoid overriding existing entries.
6613 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6614 glyph_to_char[glyph_code] = (USHORT)char_code;
6616 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6619 else
6621 ULONG n;
6623 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6624 for (n = 0; n <= 65535; n++)
6625 glyph_to_char[n] = (USHORT)n;
6628 tt_kern_table = buf;
6629 nTables = GET_BE_WORD(tt_kern_table->nTables);
6630 TRACE("version %u, nTables %u\n",
6631 GET_BE_WORD(tt_kern_table->version), nTables);
6633 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6635 for (i = 0; i < nTables; i++)
6637 struct TT_kern_subtable tt_kern_subtable_copy;
6639 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6640 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6641 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6643 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6644 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6645 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6647 /* According to the TrueType specification this is the only format
6648 * that will be properly interpreted by Windows and OS/2
6650 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6652 DWORD new_chunk, old_total = font->total_kern_pairs;
6654 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6655 glyph_to_char, NULL, 0);
6656 font->total_kern_pairs += new_chunk;
6658 if (!font->kern_pairs)
6659 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6660 font->total_kern_pairs * sizeof(*font->kern_pairs));
6661 else
6662 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6663 font->total_kern_pairs * sizeof(*font->kern_pairs));
6665 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6666 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6668 else
6669 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6671 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6674 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6675 HeapFree(GetProcessHeap(), 0, buf);
6677 if (cPairs && kern_pair)
6679 cPairs = min(cPairs, font->total_kern_pairs);
6680 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6681 LeaveCriticalSection( &freetype_cs );
6682 return cPairs;
6684 LeaveCriticalSection( &freetype_cs );
6685 return font->total_kern_pairs;
6688 #else /* HAVE_FREETYPE */
6690 /*************************************************************************/
6692 BOOL WineEngInit(void)
6694 return FALSE;
6696 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6698 return NULL;
6700 BOOL WineEngDestroyFontInstance(HFONT hfont)
6702 return FALSE;
6705 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6707 return 1;
6710 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6711 LPWORD pgi, DWORD flags)
6713 return GDI_ERROR;
6716 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6717 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6718 const MAT2* lpmat)
6720 ERR("called but we don't have FreeType\n");
6721 return GDI_ERROR;
6724 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6726 ERR("called but we don't have FreeType\n");
6727 return FALSE;
6730 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6731 OUTLINETEXTMETRICW *potm)
6733 ERR("called but we don't have FreeType\n");
6734 return 0;
6737 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6738 LPINT buffer)
6740 ERR("called but we don't have FreeType\n");
6741 return FALSE;
6744 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6745 LPABC buffer)
6747 ERR("called but we don't have FreeType\n");
6748 return FALSE;
6751 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6753 ERR("called but we don't have FreeType\n");
6754 return FALSE;
6757 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6758 LPABC buffer)
6760 ERR("called but we don't have FreeType\n");
6761 return FALSE;
6764 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6765 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6767 ERR("called but we don't have FreeType\n");
6768 return FALSE;
6771 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6772 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6774 ERR("called but we don't have FreeType\n");
6775 return FALSE;
6778 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6779 DWORD cbData)
6781 ERR("called but we don't have FreeType\n");
6782 return GDI_ERROR;
6785 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6787 ERR("called but we don't have FreeType\n");
6788 return 0;
6791 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6793 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6794 return 1;
6797 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6799 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6800 return TRUE;
6803 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6805 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6806 return NULL;
6809 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6811 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6812 return DEFAULT_CHARSET;
6815 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6817 return FALSE;
6820 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6822 FIXME("(%p, %p): stub\n", font, glyphset);
6823 return 0;
6826 BOOL WineEngFontIsLinked(GdiFont *font)
6828 return FALSE;
6831 /*************************************************************************
6832 * GetRasterizerCaps (GDI32.@)
6834 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6836 lprs->nSize = sizeof(RASTERIZER_STATUS);
6837 lprs->wFlags = 0;
6838 lprs->nLanguageID = 0;
6839 return TRUE;
6842 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6844 ERR("called but we don't have FreeType\n");
6845 return 0;
6848 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6850 ERR("called but we don't have FreeType\n");
6851 return FALSE;
6854 #endif /* HAVE_FREETYPE */