push 862965e7f7bbbfb960006fcded9111ae18c06ef6
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob96b197aeab6bd6a934efa5359325448354f62136
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/unicode.h"
88 #include "wine/debug.h"
89 #include "wine/list.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FREETYPE
95 #ifdef HAVE_FT2BUILD_H
96 #include <ft2build.h>
97 #endif
98 #ifdef HAVE_FREETYPE_FREETYPE_H
99 #include <freetype/freetype.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FTGLYPH_H
102 #include <freetype/ftglyph.h>
103 #endif
104 #ifdef HAVE_FREETYPE_TTTABLES_H
105 #include <freetype/tttables.h>
106 #endif
107 #ifdef HAVE_FREETYPE_FTTYPES_H
108 #include <freetype/fttypes.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTSNAMES_H
111 #include <freetype/ftsnames.h>
112 #endif
113 #ifdef HAVE_FREETYPE_TTNAMEID_H
114 #include <freetype/ttnameid.h>
115 #endif
116 #ifdef HAVE_FREETYPE_FTOUTLN_H
117 #include <freetype/ftoutln.h>
118 #endif
119 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
120 #include <freetype/internal/sfnt.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 #ifdef FT_MULFIX_INLINED
168 #define pFT_MulFix FT_MULFIX_INLINED
169 #else
170 MAKE_FUNCPTR(FT_MulFix);
171 #endif
172 MAKE_FUNCPTR(FT_New_Face);
173 MAKE_FUNCPTR(FT_New_Memory_Face);
174 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
175 MAKE_FUNCPTR(FT_Outline_Transform);
176 MAKE_FUNCPTR(FT_Outline_Translate);
177 MAKE_FUNCPTR(FT_Select_Charmap);
178 MAKE_FUNCPTR(FT_Set_Charmap);
179 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
180 MAKE_FUNCPTR(FT_Vector_Transform);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
183 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
184 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
185 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
186 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
187 #ifdef HAVE_FREETYPE_FTLCDFIL_H
188 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
189 #endif
190 #ifdef HAVE_FREETYPE_FTWINFNT_H
191 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
192 #endif
194 #ifdef SONAME_LIBFONTCONFIG
195 #include <fontconfig/fontconfig.h>
196 MAKE_FUNCPTR(FcConfigGetCurrent);
197 MAKE_FUNCPTR(FcFontList);
198 MAKE_FUNCPTR(FcFontSetDestroy);
199 MAKE_FUNCPTR(FcInit);
200 MAKE_FUNCPTR(FcObjectSetAdd);
201 MAKE_FUNCPTR(FcObjectSetCreate);
202 MAKE_FUNCPTR(FcObjectSetDestroy);
203 MAKE_FUNCPTR(FcPatternCreate);
204 MAKE_FUNCPTR(FcPatternDestroy);
205 MAKE_FUNCPTR(FcPatternGetBool);
206 MAKE_FUNCPTR(FcPatternGetString);
207 #endif
209 #undef MAKE_FUNCPTR
211 #ifndef FT_MAKE_TAG
212 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
213 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
214 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #endif
217 #ifndef ft_encoding_none
218 #define FT_ENCODING_NONE ft_encoding_none
219 #endif
220 #ifndef ft_encoding_ms_symbol
221 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #endif
223 #ifndef ft_encoding_unicode
224 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #endif
226 #ifndef ft_encoding_apple_roman
227 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #endif
230 #ifdef WORDS_BIGENDIAN
231 #define GET_BE_WORD(x) (x)
232 #else
233 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 #endif
236 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
237 typedef struct {
238 FT_Short height;
239 FT_Short width;
240 FT_Pos size;
241 FT_Pos x_ppem;
242 FT_Pos y_ppem;
243 FT_Short internal_leading;
244 } Bitmap_Size;
246 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
247 So to let this compile on older versions of FreeType we'll define the
248 new structure here. */
249 typedef struct {
250 FT_Short height, width;
251 FT_Pos size, x_ppem, y_ppem;
252 } My_FT_Bitmap_Size;
254 struct enum_data
256 ENUMLOGFONTEXW elf;
257 NEWTEXTMETRICEXW ntm;
258 DWORD type;
261 typedef struct tagFace {
262 struct list entry;
263 WCHAR *StyleName;
264 char *file;
265 void *font_data_ptr;
266 DWORD font_data_size;
267 FT_Long face_index;
268 FONTSIGNATURE fs;
269 FONTSIGNATURE fs_links;
270 DWORD ntmFlags;
271 FT_Fixed font_version;
272 BOOL scalable;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
278 } Face;
280 typedef struct tagFamily {
281 struct list entry;
282 const WCHAR *FamilyName;
283 struct list faces;
284 } Family;
286 typedef struct {
287 GLYPHMETRICS gm;
288 INT adv; /* These three hold to widths of the unrotated chars */
289 INT lsb;
290 INT bbx;
291 BOOL init;
292 } GM;
294 typedef struct {
295 FLOAT eM11, eM12;
296 FLOAT eM21, eM22;
297 } FMAT2;
299 typedef struct {
300 DWORD hash;
301 LOGFONTW lf;
302 FMAT2 matrix;
303 BOOL can_use_bitmap;
304 } FONT_DESC;
306 typedef struct tagHFONTLIST {
307 struct list entry;
308 HFONT hfont;
309 } HFONTLIST;
311 typedef struct {
312 struct list entry;
313 Face *face;
314 GdiFont *font;
315 } CHILD_FONT;
317 struct tagGdiFont {
318 struct list entry;
319 GM **gm;
320 DWORD gmsize;
321 struct list hfontlist;
322 OUTLINETEXTMETRICW *potm;
323 DWORD total_kern_pairs;
324 KERNINGPAIR *kern_pairs;
325 struct list child_fonts;
327 /* the following members can be accessed without locking, they are never modified after creation */
328 FT_Face ft_face;
329 struct font_mapping *mapping;
330 LPWSTR name;
331 int charset;
332 int codepage;
333 BOOL fake_italic;
334 BOOL fake_bold;
335 BYTE underline;
336 BYTE strikeout;
337 INT orientation;
338 FONT_DESC font_desc;
339 LONG aveWidth, ppem;
340 double scale_y;
341 SHORT yMax;
342 SHORT yMin;
343 DWORD ntmFlags;
344 FONTSIGNATURE fs;
345 GdiFont *base_font;
346 VOID *GSUB_Table;
347 DWORD cache_num;
350 typedef struct {
351 struct list entry;
352 const WCHAR *font_name;
353 struct list links;
354 } SYSTEM_LINKS;
356 #define GM_BLOCK_SIZE 128
357 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
359 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
360 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
361 #define UNUSED_CACHE_SIZE 10
362 static struct list child_font_list = LIST_INIT(child_font_list);
363 static struct list system_links = LIST_INIT(system_links);
365 static struct list font_subst_list = LIST_INIT(font_subst_list);
367 static struct list font_list = LIST_INIT(font_list);
369 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
370 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
371 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
373 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
374 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
380 'W','i','n','d','o','w','s',' ','N','T','\\',
381 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
382 'F','o','n','t','s','\0'};
384 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
385 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
386 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
387 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
389 static const WCHAR * const SystemFontValues[4] = {
390 System_Value,
391 OEMFont_Value,
392 FixedSys_Value,
393 NULL
396 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
397 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
399 /* Interesting and well-known (frequently-assumed!) font names */
400 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
401 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 };
402 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
403 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
404 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
405 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
406 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
407 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
409 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
410 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
411 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
412 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
413 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
414 'E','u','r','o','p','e','a','n','\0'};
415 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
416 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
417 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
418 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
419 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
420 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
421 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
422 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
423 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
424 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
425 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
426 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
428 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
429 WesternW, /*00*/
430 Central_EuropeanW,
431 CyrillicW,
432 GreekW,
433 TurkishW,
434 HebrewW,
435 ArabicW,
436 BalticW,
437 VietnameseW, /*08*/
438 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
439 ThaiW,
440 JapaneseW,
441 CHINESE_GB2312W,
442 HangulW,
443 CHINESE_BIG5W,
444 Hangul_Johab_W,
445 NULL, NULL, /*23*/
446 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
447 SymbolW /*31*/
450 typedef struct {
451 WCHAR *name;
452 INT charset;
453 } NameCs;
455 typedef struct tagFontSubst {
456 struct list entry;
457 NameCs from;
458 NameCs to;
459 } FontSubst;
461 struct font_mapping
463 struct list entry;
464 int refcount;
465 dev_t dev;
466 ino_t ino;
467 void *data;
468 size_t size;
471 static struct list mappings_list = LIST_INIT( mappings_list );
473 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
475 static CRITICAL_SECTION freetype_cs;
476 static CRITICAL_SECTION_DEBUG critsect_debug =
478 0, 0, &freetype_cs,
479 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
480 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
482 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
484 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
486 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
487 static BOOL use_default_fallback = FALSE;
489 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
491 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
492 'W','i','n','d','o','w','s',' ','N','T','\\',
493 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
494 'S','y','s','t','e','m','L','i','n','k',0};
496 /****************************************
497 * Notes on .fon files
499 * The fonts System, FixedSys and Terminal are special. There are typically multiple
500 * versions installed for different resolutions and codepages. Windows stores which one to use
501 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
502 * Key Meaning
503 * FIXEDFON.FON FixedSys
504 * FONTS.FON System
505 * OEMFONT.FON Terminal
506 * LogPixels Current dpi set by the display control panel applet
507 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
508 * also has a LogPixels value that appears to mirror this)
510 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
511 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
512 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
513 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
514 * so that makes sense.
516 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
517 * to be mapped into the registry on Windows 2000 at least).
518 * I have
519 * woafont=app850.fon
520 * ega80woa.fon=ega80850.fon
521 * ega40woa.fon=ega40850.fon
522 * cga80woa.fon=cga80850.fon
523 * cga40woa.fon=cga40850.fon
526 /* These are all structures needed for the GSUB table */
528 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
529 #define TATEGAKI_LOWER_BOUND 0x02F1
531 typedef struct {
532 DWORD version;
533 WORD ScriptList;
534 WORD FeatureList;
535 WORD LookupList;
536 } GSUB_Header;
538 typedef struct {
539 CHAR ScriptTag[4];
540 WORD Script;
541 } GSUB_ScriptRecord;
543 typedef struct {
544 WORD ScriptCount;
545 GSUB_ScriptRecord ScriptRecord[1];
546 } GSUB_ScriptList;
548 typedef struct {
549 CHAR LangSysTag[4];
550 WORD LangSys;
551 } GSUB_LangSysRecord;
553 typedef struct {
554 WORD DefaultLangSys;
555 WORD LangSysCount;
556 GSUB_LangSysRecord LangSysRecord[1];
557 } GSUB_Script;
559 typedef struct {
560 WORD LookupOrder; /* Reserved */
561 WORD ReqFeatureIndex;
562 WORD FeatureCount;
563 WORD FeatureIndex[1];
564 } GSUB_LangSys;
566 typedef struct {
567 CHAR FeatureTag[4];
568 WORD Feature;
569 } GSUB_FeatureRecord;
571 typedef struct {
572 WORD FeatureCount;
573 GSUB_FeatureRecord FeatureRecord[1];
574 } GSUB_FeatureList;
576 typedef struct {
577 WORD FeatureParams; /* Reserved */
578 WORD LookupCount;
579 WORD LookupListIndex[1];
580 } GSUB_Feature;
582 typedef struct {
583 WORD LookupCount;
584 WORD Lookup[1];
585 } GSUB_LookupList;
587 typedef struct {
588 WORD LookupType;
589 WORD LookupFlag;
590 WORD SubTableCount;
591 WORD SubTable[1];
592 } GSUB_LookupTable;
594 typedef struct {
595 WORD CoverageFormat;
596 WORD GlyphCount;
597 WORD GlyphArray[1];
598 } GSUB_CoverageFormat1;
600 typedef struct {
601 WORD Start;
602 WORD End;
603 WORD StartCoverageIndex;
604 } GSUB_RangeRecord;
606 typedef struct {
607 WORD CoverageFormat;
608 WORD RangeCount;
609 GSUB_RangeRecord RangeRecord[1];
610 } GSUB_CoverageFormat2;
612 typedef struct {
613 WORD SubstFormat; /* = 1 */
614 WORD Coverage;
615 WORD DeltaGlyphID;
616 } GSUB_SingleSubstFormat1;
618 typedef struct {
619 WORD SubstFormat; /* = 2 */
620 WORD Coverage;
621 WORD GlyphCount;
622 WORD Substitute[1];
623 }GSUB_SingleSubstFormat2;
625 #ifdef HAVE_CARBON_CARBON_H
626 static char *find_cache_dir(void)
628 FSRef ref;
629 OSErr err;
630 static char cached_path[MAX_PATH];
631 static const char *wine = "/Wine", *fonts = "/Fonts";
633 if(*cached_path) return cached_path;
635 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
636 if(err != noErr)
638 WARN("can't create cached data folder\n");
639 return NULL;
641 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
642 if(err != noErr)
644 WARN("can't create cached data path\n");
645 *cached_path = '\0';
646 return NULL;
648 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
650 ERR("Could not create full path\n");
651 *cached_path = '\0';
652 return NULL;
654 strcat(cached_path, wine);
656 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
658 WARN("Couldn't mkdir %s\n", cached_path);
659 *cached_path = '\0';
660 return NULL;
662 strcat(cached_path, fonts);
663 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
665 WARN("Couldn't mkdir %s\n", cached_path);
666 *cached_path = '\0';
667 return NULL;
669 return cached_path;
672 /******************************************************************
673 * expand_mac_font
675 * Extracts individual TrueType font files from a Mac suitcase font
676 * and saves them into the user's caches directory (see
677 * find_cache_dir()).
678 * Returns a NULL terminated array of filenames.
680 * We do this because they are apps that try to read ttf files
681 * themselves and they don't like Mac suitcase files.
683 static char **expand_mac_font(const char *path)
685 FSRef ref;
686 SInt16 res_ref;
687 OSStatus s;
688 unsigned int idx;
689 const char *out_dir;
690 const char *filename;
691 int output_len;
692 struct {
693 char **array;
694 unsigned int size, max_size;
695 } ret;
697 TRACE("path %s\n", path);
699 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
700 if(s != noErr)
702 WARN("failed to get ref\n");
703 return NULL;
706 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
707 if(s != noErr)
709 TRACE("no data fork, so trying resource fork\n");
710 res_ref = FSOpenResFile(&ref, fsRdPerm);
711 if(res_ref == -1)
713 TRACE("unable to open resource fork\n");
714 return NULL;
718 ret.size = 0;
719 ret.max_size = 10;
720 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
721 if(!ret.array)
723 CloseResFile(res_ref);
724 return NULL;
727 out_dir = find_cache_dir();
729 filename = strrchr(path, '/');
730 if(!filename) filename = path;
731 else filename++;
733 /* output filename has the form out_dir/filename_%04x.ttf */
734 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
736 UseResFile(res_ref);
737 idx = 1;
738 while(1)
740 FamRec *fam_rec;
741 unsigned short *num_faces_ptr, num_faces, face;
742 AsscEntry *assoc;
743 Handle fond;
744 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
746 fond = Get1IndResource(fond_res, idx);
747 if(!fond) break;
748 TRACE("got fond resource %d\n", idx);
749 HLock(fond);
751 fam_rec = *(FamRec**)fond;
752 num_faces_ptr = (unsigned short *)(fam_rec + 1);
753 num_faces = GET_BE_WORD(*num_faces_ptr);
754 num_faces++;
755 assoc = (AsscEntry*)(num_faces_ptr + 1);
756 TRACE("num faces %04x\n", num_faces);
757 for(face = 0; face < num_faces; face++, assoc++)
759 Handle sfnt;
760 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
761 unsigned short size, font_id;
762 char *output;
764 size = GET_BE_WORD(assoc->fontSize);
765 font_id = GET_BE_WORD(assoc->fontID);
766 if(size != 0)
768 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
769 continue;
772 TRACE("trying to load sfnt id %04x\n", font_id);
773 sfnt = GetResource(sfnt_res, font_id);
774 if(!sfnt)
776 TRACE("can't get sfnt resource %04x\n", font_id);
777 continue;
780 output = HeapAlloc(GetProcessHeap(), 0, output_len);
781 if(output)
783 int fd;
785 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
787 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
788 if(fd != -1 || errno == EEXIST)
790 if(fd != -1)
792 unsigned char *sfnt_data;
794 HLock(sfnt);
795 sfnt_data = *(unsigned char**)sfnt;
796 write(fd, sfnt_data, GetHandleSize(sfnt));
797 HUnlock(sfnt);
798 close(fd);
800 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
802 ret.max_size *= 2;
803 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
805 ret.array[ret.size++] = output;
807 else
809 WARN("unable to create %s\n", output);
810 HeapFree(GetProcessHeap(), 0, output);
813 ReleaseResource(sfnt);
815 HUnlock(fond);
816 ReleaseResource(fond);
817 idx++;
819 CloseResFile(res_ref);
821 return ret.array;
824 #endif /* HAVE_CARBON_CARBON_H */
826 static inline BOOL is_win9x(void)
828 return GetVersion() & 0x80000000;
831 This function builds an FT_Fixed from a double. It fails if the absolute
832 value of the float number is greater than 32768.
834 static inline FT_Fixed FT_FixedFromFloat(double f)
836 return f * 0x10000;
840 This function builds an FT_Fixed from a FIXED. It simply put f.value
841 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
843 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
845 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
849 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
851 Family *family;
852 Face *face;
853 const char *file;
854 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
855 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
857 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
858 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
860 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
862 if(face_name && strcmpiW(face_name, family->FamilyName))
863 continue;
864 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
866 if (!face->file)
867 continue;
868 file = strrchr(face->file, '/');
869 if(!file)
870 file = face->file;
871 else
872 file++;
873 if(!strcasecmp(file, file_nameA))
875 HeapFree(GetProcessHeap(), 0, file_nameA);
876 return face;
880 HeapFree(GetProcessHeap(), 0, file_nameA);
881 return NULL;
884 static Family *find_family_from_name(const WCHAR *name)
886 Family *family;
888 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
890 if(!strcmpiW(family->FamilyName, name))
891 return family;
894 return NULL;
897 static void DumpSubstList(void)
899 FontSubst *psub;
901 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
903 if(psub->from.charset != -1 || psub->to.charset != -1)
904 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
905 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
906 else
907 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
908 debugstr_w(psub->to.name));
910 return;
913 static LPWSTR strdupW(LPCWSTR p)
915 LPWSTR ret;
916 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
917 ret = HeapAlloc(GetProcessHeap(), 0, len);
918 memcpy(ret, p, len);
919 return ret;
922 static LPSTR strdupA(LPCSTR p)
924 LPSTR ret;
925 DWORD len = (strlen(p) + 1);
926 ret = HeapAlloc(GetProcessHeap(), 0, len);
927 memcpy(ret, p, len);
928 return ret;
931 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
932 INT from_charset)
934 FontSubst *element;
936 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
938 if(!strcmpiW(element->from.name, from_name) &&
939 (element->from.charset == from_charset ||
940 element->from.charset == -1))
941 return element;
944 return NULL;
947 #define ADD_FONT_SUBST_FORCE 1
949 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
951 FontSubst *from_exist, *to_exist;
953 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
955 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
957 list_remove(&from_exist->entry);
958 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
959 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
960 HeapFree(GetProcessHeap(), 0, from_exist);
961 from_exist = NULL;
964 if(!from_exist)
966 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
968 if(to_exist)
970 HeapFree(GetProcessHeap(), 0, subst->to.name);
971 subst->to.name = strdupW(to_exist->to.name);
974 list_add_tail(subst_list, &subst->entry);
976 return TRUE;
979 HeapFree(GetProcessHeap(), 0, subst->from.name);
980 HeapFree(GetProcessHeap(), 0, subst->to.name);
981 HeapFree(GetProcessHeap(), 0, subst);
982 return FALSE;
985 static void split_subst_info(NameCs *nc, LPSTR str)
987 CHAR *p = strrchr(str, ',');
988 DWORD len;
990 nc->charset = -1;
991 if(p && *(p+1)) {
992 nc->charset = strtol(p+1, NULL, 10);
993 *p = '\0';
995 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
996 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
997 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1000 static void LoadSubstList(void)
1002 FontSubst *psub;
1003 HKEY hkey;
1004 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1005 LPSTR value;
1006 LPVOID data;
1008 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1009 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1010 &hkey) == ERROR_SUCCESS) {
1012 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1013 &valuelen, &datalen, NULL, NULL);
1015 valuelen++; /* returned value doesn't include room for '\0' */
1016 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1017 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1019 dlen = datalen;
1020 vlen = valuelen;
1021 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1022 &dlen) == ERROR_SUCCESS) {
1023 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1025 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1026 split_subst_info(&psub->from, value);
1027 split_subst_info(&psub->to, data);
1029 /* Win 2000 doesn't allow mapping between different charsets
1030 or mapping of DEFAULT_CHARSET */
1031 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1032 psub->to.charset == DEFAULT_CHARSET) {
1033 HeapFree(GetProcessHeap(), 0, psub->to.name);
1034 HeapFree(GetProcessHeap(), 0, psub->from.name);
1035 HeapFree(GetProcessHeap(), 0, psub);
1036 } else {
1037 add_font_subst(&font_subst_list, psub, 0);
1039 /* reset dlen and vlen */
1040 dlen = datalen;
1041 vlen = valuelen;
1043 HeapFree(GetProcessHeap(), 0, data);
1044 HeapFree(GetProcessHeap(), 0, value);
1045 RegCloseKey(hkey);
1050 /*****************************************************************
1051 * get_name_table_entry
1053 * Supply the platform, encoding, language and name ids in req
1054 * and if the name exists the function will fill in the string
1055 * and string_len members. The string is owned by FreeType so
1056 * don't free it. Returns TRUE if the name is found else FALSE.
1058 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1060 FT_SfntName name;
1061 FT_UInt num_names, name_index;
1063 if(FT_IS_SFNT(ft_face))
1065 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1067 for(name_index = 0; name_index < num_names; name_index++)
1069 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1071 if((name.platform_id == req->platform_id) &&
1072 (name.encoding_id == req->encoding_id) &&
1073 (name.language_id == req->language_id) &&
1074 (name.name_id == req->name_id))
1076 req->string = name.string;
1077 req->string_len = name.string_len;
1078 return TRUE;
1083 req->string = NULL;
1084 req->string_len = 0;
1085 return FALSE;
1088 static WCHAR *get_familyname(FT_Face ft_face)
1090 WCHAR *family = NULL;
1091 FT_SfntName name;
1093 name.platform_id = TT_PLATFORM_MICROSOFT;
1094 name.encoding_id = TT_MS_ID_UNICODE_CS;
1095 name.language_id = GetUserDefaultLCID();
1096 name.name_id = TT_NAME_ID_FONT_FAMILY;
1098 if(get_name_table_entry(ft_face, &name))
1100 FT_UInt i;
1102 /* String is not nul terminated and string_len is a byte length. */
1103 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1104 for(i = 0; i < name.string_len / 2; i++)
1106 WORD *tmp = (WORD *)&name.string[i * 2];
1107 family[i] = GET_BE_WORD(*tmp);
1109 family[i] = 0;
1110 TRACE("Got localised name %s\n", debugstr_w(family));
1113 return family;
1117 /*****************************************************************
1118 * load_sfnt_table
1120 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1121 * of FreeType that don't export this function.
1124 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1127 FT_Error err;
1129 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1130 if(pFT_Load_Sfnt_Table)
1132 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1134 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1135 else /* Do it the hard way */
1137 TT_Face tt_face = (TT_Face) ft_face;
1138 SFNT_Interface *sfnt;
1139 if (FT_Version.major==2 && FT_Version.minor==0)
1141 /* 2.0.x */
1142 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1144 else
1146 /* A field was added in the middle of the structure in 2.1.x */
1147 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1149 err = sfnt->load_any(tt_face, table, offset, buf, len);
1151 #else
1152 else
1154 static int msg;
1155 if(!msg)
1157 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1158 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1159 "Please upgrade your freetype library.\n");
1160 msg++;
1162 err = FT_Err_Unimplemented_Feature;
1164 #endif
1165 return err;
1168 static inline int TestStyles(DWORD flags, DWORD styles)
1170 return (flags & styles) == styles;
1173 static int StyleOrdering(Face *face)
1175 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1176 return 3;
1177 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1178 return 2;
1179 if (TestStyles(face->ntmFlags, NTM_BOLD))
1180 return 1;
1181 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1182 return 0;
1184 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1185 debugstr_w(face->family->FamilyName),
1186 debugstr_w(face->StyleName),
1187 face->ntmFlags);
1189 return 9999;
1192 /* Add a style of face to a font family using an ordering of the list such
1193 that regular fonts come before bold and italic, and single styles come
1194 before compound styles. */
1195 static void AddFaceToFamily(Face *face, Family *family)
1197 struct list *entry;
1199 LIST_FOR_EACH( entry, &family->faces )
1201 Face *ent = LIST_ENTRY(entry, Face, entry);
1202 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1204 list_add_before( entry, &face->entry );
1207 #define ADDFONT_EXTERNAL_FONT 0x01
1208 #define ADDFONT_FORCE_BITMAP 0x02
1209 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1211 FT_Face ft_face;
1212 TT_OS2 *pOS2;
1213 TT_Header *pHeader = NULL;
1214 WCHAR *english_family, *localised_family, *StyleW;
1215 DWORD len;
1216 Family *family;
1217 Face *face;
1218 struct list *family_elem_ptr, *face_elem_ptr;
1219 FT_Error err;
1220 FT_Long face_index = 0, num_faces;
1221 #ifdef HAVE_FREETYPE_FTWINFNT_H
1222 FT_WinFNT_HeaderRec winfnt_header;
1223 #endif
1224 int i, bitmap_num, internal_leading;
1225 FONTSIGNATURE fs;
1227 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1228 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1230 #ifdef HAVE_CARBON_CARBON_H
1231 if(file && !fake_family)
1233 char **mac_list = expand_mac_font(file);
1234 if(mac_list)
1236 BOOL had_one = FALSE;
1237 char **cursor;
1238 for(cursor = mac_list; *cursor; cursor++)
1240 had_one = TRUE;
1241 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1242 HeapFree(GetProcessHeap(), 0, *cursor);
1244 HeapFree(GetProcessHeap(), 0, mac_list);
1245 if(had_one)
1246 return 1;
1249 #endif /* HAVE_CARBON_CARBON_H */
1251 do {
1252 char *family_name = fake_family;
1254 if (file)
1256 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1257 err = pFT_New_Face(library, file, face_index, &ft_face);
1258 } else
1260 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1261 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1264 if(err != 0) {
1265 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1266 return 0;
1269 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*/
1270 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1271 pFT_Done_Face(ft_face);
1272 return 0;
1275 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1276 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1277 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1278 pFT_Done_Face(ft_face);
1279 return 0;
1282 if(FT_IS_SFNT(ft_face))
1284 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1285 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1286 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1288 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1289 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1290 pFT_Done_Face(ft_face);
1291 return 0;
1294 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1295 we don't want to load these. */
1296 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1298 FT_ULong len = 0;
1300 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1302 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1303 pFT_Done_Face(ft_face);
1304 return 0;
1309 if(!ft_face->family_name || !ft_face->style_name) {
1310 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1311 pFT_Done_Face(ft_face);
1312 return 0;
1315 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1317 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1318 pFT_Done_Face(ft_face);
1319 return 0;
1322 if (target_family)
1324 localised_family = get_familyname(ft_face);
1325 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1327 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1328 HeapFree(GetProcessHeap(), 0, localised_family);
1329 num_faces = ft_face->num_faces;
1330 pFT_Done_Face(ft_face);
1331 continue;
1333 HeapFree(GetProcessHeap(), 0, localised_family);
1336 if(!family_name)
1337 family_name = ft_face->family_name;
1339 bitmap_num = 0;
1340 do {
1341 My_FT_Bitmap_Size *size = NULL;
1342 FT_ULong tmp_size;
1344 if(!FT_IS_SCALABLE(ft_face))
1345 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1347 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1348 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1349 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1351 localised_family = NULL;
1352 if(!fake_family) {
1353 localised_family = get_familyname(ft_face);
1354 if(localised_family && !strcmpiW(localised_family, english_family)) {
1355 HeapFree(GetProcessHeap(), 0, localised_family);
1356 localised_family = NULL;
1360 family = NULL;
1361 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1362 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1363 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1364 break;
1365 family = NULL;
1367 if(!family) {
1368 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1369 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1370 list_init(&family->faces);
1371 list_add_tail(&font_list, &family->entry);
1373 if(localised_family) {
1374 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1375 subst->from.name = strdupW(english_family);
1376 subst->from.charset = -1;
1377 subst->to.name = strdupW(localised_family);
1378 subst->to.charset = -1;
1379 add_font_subst(&font_subst_list, subst, 0);
1382 HeapFree(GetProcessHeap(), 0, localised_family);
1383 HeapFree(GetProcessHeap(), 0, english_family);
1385 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1386 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1387 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1389 internal_leading = 0;
1390 memset(&fs, 0, sizeof(fs));
1392 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1393 if(pOS2) {
1394 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1395 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1396 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1397 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1398 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1399 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1400 if(pOS2->version == 0) {
1401 FT_UInt dummy;
1403 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1404 fs.fsCsb[0] |= FS_LATIN1;
1405 else
1406 fs.fsCsb[0] |= FS_SYMBOL;
1409 #ifdef HAVE_FREETYPE_FTWINFNT_H
1410 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1411 CHARSETINFO csi;
1412 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1413 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1414 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1415 fs = csi.fs;
1416 internal_leading = winfnt_header.internal_leading;
1418 #endif
1420 face_elem_ptr = list_head(&family->faces);
1421 while(face_elem_ptr) {
1422 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1423 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1424 if(!strcmpiW(face->StyleName, StyleW) &&
1425 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1426 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1427 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1428 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1430 if(fake_family) {
1431 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1432 HeapFree(GetProcessHeap(), 0, StyleW);
1433 pFT_Done_Face(ft_face);
1434 return 1;
1436 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1437 TRACE("Original font is newer so skipping this one\n");
1438 HeapFree(GetProcessHeap(), 0, StyleW);
1439 pFT_Done_Face(ft_face);
1440 return 1;
1441 } else {
1442 TRACE("Replacing original with this one\n");
1443 list_remove(&face->entry);
1444 HeapFree(GetProcessHeap(), 0, face->file);
1445 HeapFree(GetProcessHeap(), 0, face->StyleName);
1446 HeapFree(GetProcessHeap(), 0, face);
1447 break;
1451 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1452 face->cached_enum_data = NULL;
1453 face->StyleName = StyleW;
1454 if (file)
1456 face->file = strdupA(file);
1457 face->font_data_ptr = NULL;
1458 face->font_data_size = 0;
1460 else
1462 face->file = NULL;
1463 face->font_data_ptr = font_data_ptr;
1464 face->font_data_size = font_data_size;
1466 face->face_index = face_index;
1467 face->ntmFlags = 0;
1468 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1469 face->ntmFlags |= NTM_ITALIC;
1470 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1471 face->ntmFlags |= NTM_BOLD;
1472 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1473 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1474 face->family = family;
1475 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1476 face->fs = fs;
1477 memset(&face->fs_links, 0, sizeof(face->fs_links));
1479 if(FT_IS_SCALABLE(ft_face)) {
1480 memset(&face->size, 0, sizeof(face->size));
1481 face->scalable = TRUE;
1482 } else {
1483 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1484 size->height, size->width, size->size >> 6,
1485 size->x_ppem >> 6, size->y_ppem >> 6);
1486 face->size.height = size->height;
1487 face->size.width = size->width;
1488 face->size.size = size->size;
1489 face->size.x_ppem = size->x_ppem;
1490 face->size.y_ppem = size->y_ppem;
1491 face->size.internal_leading = internal_leading;
1492 face->scalable = FALSE;
1495 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1496 tmp_size = 0;
1497 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1499 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1500 face->ntmFlags |= NTM_PS_OPENTYPE;
1503 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1504 face->fs.fsCsb[0], face->fs.fsCsb[1],
1505 face->fs.fsUsb[0], face->fs.fsUsb[1],
1506 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1509 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1510 for(i = 0; i < ft_face->num_charmaps; i++) {
1511 switch(ft_face->charmaps[i]->encoding) {
1512 case FT_ENCODING_UNICODE:
1513 case FT_ENCODING_APPLE_ROMAN:
1514 face->fs.fsCsb[0] |= FS_LATIN1;
1515 break;
1516 case FT_ENCODING_MS_SYMBOL:
1517 face->fs.fsCsb[0] |= FS_SYMBOL;
1518 break;
1519 default:
1520 break;
1525 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1526 have_installed_roman_font = TRUE;
1528 AddFaceToFamily(face, family);
1530 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1532 num_faces = ft_face->num_faces;
1533 pFT_Done_Face(ft_face);
1534 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1535 debugstr_w(StyleW));
1536 } while(num_faces > ++face_index);
1537 return num_faces;
1540 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1542 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1545 static void DumpFontList(void)
1547 Family *family;
1548 Face *face;
1549 struct list *family_elem_ptr, *face_elem_ptr;
1551 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1552 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1553 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1554 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1555 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1556 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1557 if(!face->scalable)
1558 TRACE(" %d", face->size.height);
1559 TRACE("\n");
1562 return;
1565 /***********************************************************
1566 * The replacement list is a way to map an entire font
1567 * family onto another family. For example adding
1569 * [HKCU\Software\Wine\Fonts\Replacements]
1570 * "Wingdings"="Winedings"
1572 * would enumerate the Winedings font both as Winedings and
1573 * Wingdings. However if a real Wingdings font is present the
1574 * replacement does not take place.
1577 static void LoadReplaceList(void)
1579 HKEY hkey;
1580 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1581 LPWSTR value;
1582 LPVOID data;
1583 Family *family;
1584 Face *face;
1585 struct list *family_elem_ptr, *face_elem_ptr;
1586 CHAR familyA[400];
1588 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1589 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1591 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1592 &valuelen, &datalen, NULL, NULL);
1594 valuelen++; /* returned value doesn't include room for '\0' */
1595 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1596 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1598 dlen = datalen;
1599 vlen = valuelen;
1600 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1601 &dlen) == ERROR_SUCCESS) {
1602 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1603 /* "NewName"="Oldname" */
1604 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1606 /* Find the old family and hence all of the font files
1607 in that family */
1608 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1609 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1610 if(!strcmpiW(family->FamilyName, data)) {
1611 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1612 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1613 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1614 debugstr_w(face->StyleName), familyA);
1615 /* Now add a new entry with the new family name */
1616 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1618 break;
1621 /* reset dlen and vlen */
1622 dlen = datalen;
1623 vlen = valuelen;
1625 HeapFree(GetProcessHeap(), 0, data);
1626 HeapFree(GetProcessHeap(), 0, value);
1627 RegCloseKey(hkey);
1631 /*************************************************************
1632 * init_system_links
1634 static BOOL init_system_links(void)
1636 HKEY hkey;
1637 BOOL ret = FALSE;
1638 DWORD type, max_val, max_data, val_len, data_len, index;
1639 WCHAR *value, *data;
1640 WCHAR *entry, *next;
1641 SYSTEM_LINKS *font_link, *system_font_link;
1642 CHILD_FONT *child_font;
1643 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1644 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1645 FONTSIGNATURE fs;
1646 Family *family;
1647 Face *face;
1648 FontSubst *psub;
1650 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1652 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1653 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1654 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1655 val_len = max_val + 1;
1656 data_len = max_data;
1657 index = 0;
1658 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1660 memset(&fs, 0, sizeof(fs));
1661 psub = get_font_subst(&font_subst_list, value, -1);
1662 /* Don't store fonts that are only substitutes for other fonts */
1663 if(psub)
1665 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1666 goto next;
1668 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1669 font_link->font_name = strdupW(value);
1670 list_init(&font_link->links);
1671 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1673 WCHAR *face_name;
1674 CHILD_FONT *child_font;
1676 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1678 next = entry + strlenW(entry) + 1;
1680 face_name = strchrW(entry, ',');
1681 if(face_name)
1683 *face_name++ = 0;
1684 while(isspaceW(*face_name))
1685 face_name++;
1687 psub = get_font_subst(&font_subst_list, face_name, -1);
1688 if(psub)
1689 face_name = psub->to.name;
1691 face = find_face_from_filename(entry, face_name);
1692 if(!face)
1694 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1695 continue;
1698 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1699 child_font->face = face;
1700 child_font->font = NULL;
1701 fs.fsCsb[0] |= face->fs.fsCsb[0];
1702 fs.fsCsb[1] |= face->fs.fsCsb[1];
1703 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1704 list_add_tail(&font_link->links, &child_font->entry);
1706 family = find_family_from_name(font_link->font_name);
1707 if(family)
1709 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1711 face->fs_links = fs;
1714 list_add_tail(&system_links, &font_link->entry);
1715 next:
1716 val_len = max_val + 1;
1717 data_len = max_data;
1720 HeapFree(GetProcessHeap(), 0, value);
1721 HeapFree(GetProcessHeap(), 0, data);
1722 RegCloseKey(hkey);
1725 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1726 that Tahoma has */
1728 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1729 system_font_link->font_name = strdupW(System);
1730 list_init(&system_font_link->links);
1732 face = find_face_from_filename(tahoma_ttf, Tahoma);
1733 if(face)
1735 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1736 child_font->face = face;
1737 child_font->font = NULL;
1738 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1739 list_add_tail(&system_font_link->links, &child_font->entry);
1741 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1743 if(!strcmpiW(font_link->font_name, Tahoma))
1745 CHILD_FONT *font_link_entry;
1746 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1748 CHILD_FONT *new_child;
1749 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1750 new_child->face = font_link_entry->face;
1751 new_child->font = NULL;
1752 list_add_tail(&system_font_link->links, &new_child->entry);
1754 break;
1757 list_add_tail(&system_links, &system_font_link->entry);
1758 return ret;
1761 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1763 DIR *dir;
1764 struct dirent *dent;
1765 char path[MAX_PATH];
1767 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1769 dir = opendir(dirname);
1770 if(!dir) {
1771 WARN("Can't open directory %s\n", debugstr_a(dirname));
1772 return FALSE;
1774 while((dent = readdir(dir)) != NULL) {
1775 struct stat statbuf;
1777 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1778 continue;
1780 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1782 sprintf(path, "%s/%s", dirname, dent->d_name);
1784 if(stat(path, &statbuf) == -1)
1786 WARN("Can't stat %s\n", debugstr_a(path));
1787 continue;
1789 if(S_ISDIR(statbuf.st_mode))
1790 ReadFontDir(path, external_fonts);
1791 else
1792 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1794 closedir(dir);
1795 return TRUE;
1798 static void load_fontconfig_fonts(void)
1800 #ifdef SONAME_LIBFONTCONFIG
1801 void *fc_handle = NULL;
1802 FcConfig *config;
1803 FcPattern *pat;
1804 FcObjectSet *os;
1805 FcFontSet *fontset;
1806 int i, len;
1807 char *file;
1808 const char *ext;
1810 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1811 if(!fc_handle) {
1812 TRACE("Wine cannot find the fontconfig library (%s).\n",
1813 SONAME_LIBFONTCONFIG);
1814 return;
1816 #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;}
1817 LOAD_FUNCPTR(FcConfigGetCurrent);
1818 LOAD_FUNCPTR(FcFontList);
1819 LOAD_FUNCPTR(FcFontSetDestroy);
1820 LOAD_FUNCPTR(FcInit);
1821 LOAD_FUNCPTR(FcObjectSetAdd);
1822 LOAD_FUNCPTR(FcObjectSetCreate);
1823 LOAD_FUNCPTR(FcObjectSetDestroy);
1824 LOAD_FUNCPTR(FcPatternCreate);
1825 LOAD_FUNCPTR(FcPatternDestroy);
1826 LOAD_FUNCPTR(FcPatternGetBool);
1827 LOAD_FUNCPTR(FcPatternGetString);
1828 #undef LOAD_FUNCPTR
1830 if(!pFcInit()) return;
1832 config = pFcConfigGetCurrent();
1833 pat = pFcPatternCreate();
1834 os = pFcObjectSetCreate();
1835 pFcObjectSetAdd(os, FC_FILE);
1836 pFcObjectSetAdd(os, FC_SCALABLE);
1837 fontset = pFcFontList(config, pat, os);
1838 if(!fontset) return;
1839 for(i = 0; i < fontset->nfont; i++) {
1840 FcBool scalable;
1842 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1843 continue;
1844 TRACE("fontconfig: %s\n", file);
1846 /* We're just interested in OT/TT fonts for now, so this hack just
1847 picks up the scalable fonts without extensions .pf[ab] to save time
1848 loading every other font */
1850 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1852 TRACE("not scalable\n");
1853 continue;
1856 len = strlen( file );
1857 if(len < 4) continue;
1858 ext = &file[ len - 3 ];
1859 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1860 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1862 pFcFontSetDestroy(fontset);
1863 pFcObjectSetDestroy(os);
1864 pFcPatternDestroy(pat);
1865 sym_not_found:
1866 #endif
1867 return;
1870 static BOOL load_font_from_data_dir(LPCWSTR file)
1872 BOOL ret = FALSE;
1873 const char *data_dir = wine_get_data_dir();
1875 if (!data_dir) data_dir = wine_get_build_dir();
1877 if (data_dir)
1879 INT len;
1880 char *unix_name;
1882 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1884 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1886 strcpy(unix_name, data_dir);
1887 strcat(unix_name, "/fonts/");
1889 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1891 EnterCriticalSection( &freetype_cs );
1892 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1893 LeaveCriticalSection( &freetype_cs );
1894 HeapFree(GetProcessHeap(), 0, unix_name);
1896 return ret;
1899 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1901 static const WCHAR slashW[] = {'\\','\0'};
1902 BOOL ret = FALSE;
1903 WCHAR windowsdir[MAX_PATH];
1904 char *unixname;
1906 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1907 strcatW(windowsdir, fontsW);
1908 strcatW(windowsdir, slashW);
1909 strcatW(windowsdir, file);
1910 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1911 EnterCriticalSection( &freetype_cs );
1912 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1913 LeaveCriticalSection( &freetype_cs );
1914 HeapFree(GetProcessHeap(), 0, unixname);
1916 return ret;
1919 static void load_system_fonts(void)
1921 HKEY hkey;
1922 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1923 const WCHAR * const *value;
1924 DWORD dlen, type;
1925 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1926 char *unixname;
1928 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1929 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1930 strcatW(windowsdir, fontsW);
1931 for(value = SystemFontValues; *value; value++) {
1932 dlen = sizeof(data);
1933 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1934 type == REG_SZ) {
1935 BOOL added = FALSE;
1937 sprintfW(pathW, fmtW, windowsdir, data);
1938 if((unixname = wine_get_unix_file_name(pathW))) {
1939 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1940 HeapFree(GetProcessHeap(), 0, unixname);
1942 if (!added)
1943 load_font_from_data_dir(data);
1946 RegCloseKey(hkey);
1950 /*************************************************************
1952 * This adds registry entries for any externally loaded fonts
1953 * (fonts from fontconfig or FontDirs). It also deletes entries
1954 * of no longer existing fonts.
1957 static void update_reg_entries(void)
1959 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1960 LPWSTR valueW;
1961 DWORD len, len_fam;
1962 Family *family;
1963 Face *face;
1964 struct list *family_elem_ptr, *face_elem_ptr;
1965 WCHAR *file;
1966 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1967 static const WCHAR spaceW[] = {' ', '\0'};
1968 char *path;
1970 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1971 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1972 ERR("Can't create Windows font reg key\n");
1973 goto end;
1976 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1977 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1978 ERR("Can't create Windows font reg key\n");
1979 goto end;
1982 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1983 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1984 ERR("Can't create external font reg key\n");
1985 goto end;
1988 /* enumerate the fonts and add external ones to the two keys */
1990 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1991 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1992 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1993 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1994 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1995 if(!face->external) continue;
1996 len = len_fam;
1997 if (!(face->ntmFlags & NTM_REGULAR))
1998 len = len_fam + strlenW(face->StyleName) + 1;
1999 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2000 strcpyW(valueW, family->FamilyName);
2001 if(len != len_fam) {
2002 strcatW(valueW, spaceW);
2003 strcatW(valueW, face->StyleName);
2005 strcatW(valueW, TrueType);
2007 file = wine_get_dos_file_name(face->file);
2008 if(file)
2009 len = strlenW(file) + 1;
2010 else
2012 if((path = strrchr(face->file, '/')) == NULL)
2013 path = face->file;
2014 else
2015 path++;
2016 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2018 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2019 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2021 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2022 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2023 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2025 HeapFree(GetProcessHeap(), 0, file);
2026 HeapFree(GetProcessHeap(), 0, valueW);
2029 end:
2030 if(external_key) RegCloseKey(external_key);
2031 if(win9x_key) RegCloseKey(win9x_key);
2032 if(winnt_key) RegCloseKey(winnt_key);
2033 return;
2036 static void delete_external_font_keys(void)
2038 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2039 DWORD dlen, vlen, datalen, valuelen, i, type;
2040 LPWSTR valueW;
2041 LPVOID data;
2043 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2044 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2045 ERR("Can't create Windows font reg key\n");
2046 goto end;
2049 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2050 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2051 ERR("Can't create Windows font reg key\n");
2052 goto end;
2055 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2056 ERR("Can't create external font reg key\n");
2057 goto end;
2060 /* Delete all external fonts added last time */
2062 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2063 &valuelen, &datalen, NULL, NULL);
2064 valuelen++; /* returned value doesn't include room for '\0' */
2065 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2066 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2068 dlen = datalen * sizeof(WCHAR);
2069 vlen = valuelen;
2070 i = 0;
2071 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2072 &dlen) == ERROR_SUCCESS) {
2074 RegDeleteValueW(winnt_key, valueW);
2075 RegDeleteValueW(win9x_key, valueW);
2076 /* reset dlen and vlen */
2077 dlen = datalen;
2078 vlen = valuelen;
2080 HeapFree(GetProcessHeap(), 0, data);
2081 HeapFree(GetProcessHeap(), 0, valueW);
2083 /* Delete the old external fonts key */
2084 RegCloseKey(external_key);
2085 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2087 end:
2088 if(win9x_key) RegCloseKey(win9x_key);
2089 if(winnt_key) RegCloseKey(winnt_key);
2092 /*************************************************************
2093 * WineEngAddFontResourceEx
2096 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2098 INT ret = 0;
2100 GDI_CheckNotLock();
2102 if (ft_handle) /* do it only if we have freetype up and running */
2104 char *unixname;
2106 if(flags)
2107 FIXME("Ignoring flags %x\n", flags);
2109 if((unixname = wine_get_unix_file_name(file)))
2111 EnterCriticalSection( &freetype_cs );
2112 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2113 LeaveCriticalSection( &freetype_cs );
2114 HeapFree(GetProcessHeap(), 0, unixname);
2116 if (!ret && !strchrW(file, '\\')) {
2117 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2118 ret = load_font_from_winfonts_dir(file);
2119 if (!ret) {
2120 /* Try in datadir/fonts (or builddir/fonts),
2121 * needed for Magic the Gathering Online
2123 ret = load_font_from_data_dir(file);
2127 return ret;
2130 /*************************************************************
2131 * WineEngAddFontMemResourceEx
2134 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2136 GDI_CheckNotLock();
2138 if (ft_handle) /* do it only if we have freetype up and running */
2140 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2142 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2143 memcpy(pFontCopy, pbFont, cbFont);
2145 EnterCriticalSection( &freetype_cs );
2146 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2147 LeaveCriticalSection( &freetype_cs );
2149 if (*pcFonts == 0)
2151 TRACE("AddFontToList failed\n");
2152 HeapFree(GetProcessHeap(), 0, pFontCopy);
2153 return NULL;
2155 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2156 * For now return something unique but quite random
2158 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2159 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2162 *pcFonts = 0;
2163 return 0;
2166 /*************************************************************
2167 * WineEngRemoveFontResourceEx
2170 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2172 GDI_CheckNotLock();
2173 FIXME(":stub\n");
2174 return TRUE;
2177 static const struct nls_update_font_list
2179 UINT ansi_cp, oem_cp;
2180 const char *oem, *fixed, *system;
2181 const char *courier, *serif, *small, *sserif;
2182 /* these are for font substitutes */
2183 const char *shelldlg, *tmsrmn;
2184 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2185 *helv_0, *tmsrmn_0;
2186 const struct subst
2188 const char *from, *to;
2189 } arial_0, courier_new_0, times_new_roman_0;
2190 } nls_update_font_list[] =
2192 /* Latin 1 (United States) */
2193 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2194 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2195 "Tahoma","Times New Roman",
2196 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2197 { 0 }, { 0 }, { 0 }
2199 /* Latin 1 (Multilingual) */
2200 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "Tahoma","Times New Roman", /* FIXME unverified */
2203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2204 { 0 }, { 0 }, { 0 }
2206 /* Eastern Europe */
2207 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2208 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 "Fixedsys,238", "System,238",
2211 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2212 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2213 { "Arial CE,0", "Arial,238" },
2214 { "Courier New CE,0", "Courier New,238" },
2215 { "Times New Roman CE,0", "Times New Roman,238" }
2217 /* Cyrillic */
2218 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2219 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2220 "Tahoma","Times New Roman", /* FIXME unverified */
2221 "Fixedsys,204", "System,204",
2222 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2223 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2224 { "Arial Cyr,0", "Arial,204" },
2225 { "Courier New Cyr,0", "Courier New,204" },
2226 { "Times New Roman Cyr,0", "Times New Roman,204" }
2228 /* Greek */
2229 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2230 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2231 "Tahoma","Times New Roman", /* FIXME unverified */
2232 "Fixedsys,161", "System,161",
2233 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2234 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2235 { "Arial Greek,0", "Arial,161" },
2236 { "Courier New Greek,0", "Courier New,161" },
2237 { "Times New Roman Greek,0", "Times New Roman,161" }
2239 /* Turkish */
2240 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2241 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2242 "Tahoma","Times New Roman", /* FIXME unverified */
2243 "Fixedsys,162", "System,162",
2244 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2245 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2246 { "Arial Tur,0", "Arial,162" },
2247 { "Courier New Tur,0", "Courier New,162" },
2248 { "Times New Roman Tur,0", "Times New Roman,162" }
2250 /* Hebrew */
2251 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2252 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2253 "Tahoma","Times New Roman", /* FIXME unverified */
2254 "Fixedsys,177", "System,177",
2255 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2256 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2257 { 0 }, { 0 }, { 0 }
2259 /* Arabic */
2260 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2261 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2262 "Tahoma","Times New Roman", /* FIXME unverified */
2263 "Fixedsys,178", "System,178",
2264 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2265 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2266 { 0 }, { 0 }, { 0 }
2268 /* Baltic */
2269 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2270 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2271 "Tahoma","Times New Roman", /* FIXME unverified */
2272 "Fixedsys,186", "System,186",
2273 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2274 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2275 { "Arial Baltic,0", "Arial,186" },
2276 { "Courier New Baltic,0", "Courier New,186" },
2277 { "Times New Roman Baltic,0", "Times New Roman,186" }
2279 /* Vietnamese */
2280 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2281 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2282 "Tahoma","Times New Roman", /* FIXME unverified */
2283 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2284 { 0 }, { 0 }, { 0 }
2286 /* Thai */
2287 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2288 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2289 "Tahoma","Times New Roman", /* FIXME unverified */
2290 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2291 { 0 }, { 0 }, { 0 }
2293 /* Japanese */
2294 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2295 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2296 "MS UI Gothic","MS Serif",
2297 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2298 { 0 }, { 0 }, { 0 }
2300 /* Chinese Simplified */
2301 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2302 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2303 "SimSun", "NSimSun",
2304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2305 { 0 }, { 0 }, { 0 }
2307 /* Korean */
2308 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2309 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2310 "Gulim", "Batang",
2311 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2312 { 0 }, { 0 }, { 0 }
2314 /* Chinese Traditional */
2315 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2316 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2317 "PMingLiU", "MingLiU",
2318 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2319 { 0 }, { 0 }, { 0 }
2323 static const WCHAR *font_links_list[] =
2325 Lucida_Sans_Unicode,
2326 Microsoft_Sans_Serif,
2327 Tahoma
2330 static const struct font_links_defaults_list
2332 /* Keyed off substitution for "MS Shell Dlg" */
2333 const WCHAR *shelldlg;
2334 /* Maximum of four substitutes, plus terminating NULL pointer */
2335 const WCHAR *substitutes[5];
2336 } font_links_defaults_list[] =
2338 /* Non East-Asian */
2339 { Tahoma, /* FIXME unverified ordering */
2340 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2342 /* Below lists are courtesy of
2343 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2345 /* Japanese */
2346 { MS_UI_Gothic,
2347 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2349 /* Chinese Simplified */
2350 { SimSun,
2351 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2353 /* Korean */
2354 { Gulim,
2355 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2357 /* Chinese Traditional */
2358 { PMingLiU,
2359 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2363 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2365 return ( ansi_cp == 932 /* CP932 for Japanese */
2366 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2367 || ansi_cp == 949 /* CP949 for Korean */
2368 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2371 static inline HKEY create_fonts_NT_registry_key(void)
2373 HKEY hkey = 0;
2375 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2376 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2377 return hkey;
2380 static inline HKEY create_fonts_9x_registry_key(void)
2382 HKEY hkey = 0;
2384 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2385 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2386 return hkey;
2389 static inline HKEY create_config_fonts_registry_key(void)
2391 HKEY hkey = 0;
2393 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2394 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2395 return hkey;
2398 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2400 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2401 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2402 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2403 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2406 static void set_value_key(HKEY hkey, const char *name, const char *value)
2408 if (value)
2409 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2410 else if (name)
2411 RegDeleteValueA(hkey, name);
2414 static void update_font_info(void)
2416 char buf[40], cpbuf[40];
2417 DWORD len, type;
2418 HKEY hkey = 0;
2419 UINT i, ansi_cp = 0, oem_cp = 0;
2420 BOOL done = FALSE;
2422 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2423 return;
2425 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2426 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2427 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2428 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2429 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2431 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2432 if (is_dbcs_ansi_cp(ansi_cp))
2433 use_default_fallback = TRUE;
2435 len = sizeof(buf);
2436 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2438 if (!strcmp( buf, cpbuf )) /* already set correctly */
2440 RegCloseKey(hkey);
2441 return;
2443 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2445 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2447 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2448 RegCloseKey(hkey);
2450 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2452 HKEY hkey;
2454 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2455 nls_update_font_list[i].oem_cp == oem_cp)
2457 hkey = create_config_fonts_registry_key();
2458 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2459 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2460 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2461 RegCloseKey(hkey);
2463 hkey = create_fonts_NT_registry_key();
2464 add_font_list(hkey, &nls_update_font_list[i]);
2465 RegCloseKey(hkey);
2467 hkey = create_fonts_9x_registry_key();
2468 add_font_list(hkey, &nls_update_font_list[i]);
2469 RegCloseKey(hkey);
2471 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2473 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2474 strlen(nls_update_font_list[i].shelldlg)+1);
2475 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2476 strlen(nls_update_font_list[i].tmsrmn)+1);
2478 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2479 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2480 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2481 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2482 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2483 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2484 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2485 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2487 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2488 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2489 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2491 RegCloseKey(hkey);
2493 done = TRUE;
2495 else
2497 /* Delete the FontSubstitutes from other locales */
2498 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2500 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2501 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2502 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2503 RegCloseKey(hkey);
2507 if (!done)
2508 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2510 /* Clear out system links */
2511 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2514 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2516 const WCHAR *value;
2517 int i;
2518 FontSubst *psub;
2519 Family *family;
2520 Face *face;
2521 const char *file;
2522 WCHAR *fileW;
2523 int fileLen;
2524 WCHAR buff[MAX_PATH];
2525 WCHAR *data;
2526 int entryLen;
2528 static const WCHAR comma[] = {',',0};
2530 RegDeleteValueW(hkey, name);
2531 if (values)
2533 data = buff;
2534 data[0] = '\0';
2535 for (i = 0; values[i] != NULL; i++)
2537 value = values[i];
2538 if (!strcmpiW(name,value))
2539 continue;
2540 psub = get_font_subst(&font_subst_list, value, -1);
2541 if(psub)
2542 value = psub->to.name;
2543 family = find_family_from_name(value);
2544 if (!family)
2545 continue;
2546 file = NULL;
2547 /* Use first extant filename for this Family */
2548 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2550 if (!face->file)
2551 continue;
2552 file = strrchr(face->file, '/');
2553 if (!file)
2554 file = face->file;
2555 else
2556 file++;
2557 break;
2559 if (!file)
2560 continue;
2561 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2562 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2563 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2564 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2565 if (sizeof(buff)-(data-buff) < entryLen + 1)
2567 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2568 HeapFree(GetProcessHeap(), 0, fileW);
2569 break;
2571 strcpyW(data, fileW);
2572 strcatW(data, comma);
2573 strcatW(data, value);
2574 data += entryLen;
2575 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2576 HeapFree(GetProcessHeap(), 0, fileW);
2578 if (data != buff)
2580 *data='\0';
2581 data++;
2582 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2583 } else
2584 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2585 } else
2586 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2589 static void update_system_links(void)
2591 HKEY hkey = 0;
2592 UINT i, j;
2593 BOOL done = FALSE;
2594 DWORD disposition;
2595 FontSubst *psub;
2597 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2599 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2601 if (disposition == REG_OPENED_EXISTING_KEY)
2603 TRACE("SystemLink key already exists, doing nothing\n");
2604 RegCloseKey(hkey);
2605 return;
2608 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2609 if (!psub) {
2610 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2611 RegCloseKey(hkey);
2612 return;
2615 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2617 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2619 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2620 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2622 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2623 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2624 done = TRUE;
2626 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2628 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2631 RegCloseKey(hkey);
2632 if (!done)
2633 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2634 } else
2635 WARN("failed to create SystemLink key\n");
2639 static BOOL init_freetype(void)
2641 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2642 if(!ft_handle) {
2643 WINE_MESSAGE(
2644 "Wine cannot find the FreeType font library. To enable Wine to\n"
2645 "use TrueType fonts please install a version of FreeType greater than\n"
2646 "or equal to 2.0.5.\n"
2647 "http://www.freetype.org\n");
2648 return FALSE;
2651 #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;}
2653 LOAD_FUNCPTR(FT_Vector_Unit)
2654 LOAD_FUNCPTR(FT_Done_Face)
2655 LOAD_FUNCPTR(FT_Get_Char_Index)
2656 LOAD_FUNCPTR(FT_Get_Module)
2657 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2658 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2659 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2660 LOAD_FUNCPTR(FT_Init_FreeType)
2661 LOAD_FUNCPTR(FT_Load_Glyph)
2662 LOAD_FUNCPTR(FT_Matrix_Multiply)
2663 #ifndef FT_MULFIX_INLINED
2664 LOAD_FUNCPTR(FT_MulFix)
2665 #endif
2666 LOAD_FUNCPTR(FT_New_Face)
2667 LOAD_FUNCPTR(FT_New_Memory_Face)
2668 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2669 LOAD_FUNCPTR(FT_Outline_Transform)
2670 LOAD_FUNCPTR(FT_Outline_Translate)
2671 LOAD_FUNCPTR(FT_Select_Charmap)
2672 LOAD_FUNCPTR(FT_Set_Charmap)
2673 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2674 LOAD_FUNCPTR(FT_Vector_Transform)
2675 LOAD_FUNCPTR(FT_Render_Glyph)
2677 #undef LOAD_FUNCPTR
2678 /* Don't warn if these ones are missing */
2679 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2680 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2681 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2682 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2683 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2684 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2685 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2686 #endif
2687 #ifdef HAVE_FREETYPE_FTWINFNT_H
2688 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2689 #endif
2690 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2691 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2692 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2693 <= 2.0.3 has FT_Sqrt64 */
2694 goto sym_not_found;
2697 if(pFT_Init_FreeType(&library) != 0) {
2698 ERR("Can't init FreeType library\n");
2699 wine_dlclose(ft_handle, NULL, 0);
2700 ft_handle = NULL;
2701 return FALSE;
2703 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2704 if (pFT_Library_Version)
2705 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2707 if (FT_Version.major<=0)
2709 FT_Version.major=2;
2710 FT_Version.minor=0;
2711 FT_Version.patch=5;
2713 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2714 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2715 ((FT_Version.minor << 8) & 0x00ff00) |
2716 ((FT_Version.patch ) & 0x0000ff);
2718 return TRUE;
2720 sym_not_found:
2721 WINE_MESSAGE(
2722 "Wine cannot find certain functions that it needs inside the FreeType\n"
2723 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2724 "FreeType to at least version 2.0.5.\n"
2725 "http://www.freetype.org\n");
2726 wine_dlclose(ft_handle, NULL, 0);
2727 ft_handle = NULL;
2728 return FALSE;
2731 /*************************************************************
2732 * WineEngInit
2734 * Initialize FreeType library and create a list of available faces
2736 BOOL WineEngInit(void)
2738 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2739 static const WCHAR pathW[] = {'P','a','t','h',0};
2740 HKEY hkey;
2741 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2742 WCHAR windowsdir[MAX_PATH];
2743 char *unixname;
2744 HANDLE font_mutex;
2745 const char *data_dir;
2747 TRACE("\n");
2749 /* update locale dependent font info in registry */
2750 update_font_info();
2752 if(!init_freetype()) return FALSE;
2754 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2755 ERR("Failed to create font mutex\n");
2756 return FALSE;
2758 WaitForSingleObject(font_mutex, INFINITE);
2760 delete_external_font_keys();
2762 /* load the system bitmap fonts */
2763 load_system_fonts();
2765 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2766 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2767 strcatW(windowsdir, fontsW);
2768 if((unixname = wine_get_unix_file_name(windowsdir)))
2770 ReadFontDir(unixname, FALSE);
2771 HeapFree(GetProcessHeap(), 0, unixname);
2774 /* load the system truetype fonts */
2775 data_dir = wine_get_data_dir();
2776 if (!data_dir) data_dir = wine_get_build_dir();
2777 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2778 strcpy(unixname, data_dir);
2779 strcat(unixname, "/fonts/");
2780 ReadFontDir(unixname, TRUE);
2781 HeapFree(GetProcessHeap(), 0, unixname);
2784 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2785 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2786 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2787 will skip these. */
2788 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2789 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2790 &hkey) == ERROR_SUCCESS) {
2791 LPWSTR data, valueW;
2792 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2793 &valuelen, &datalen, NULL, NULL);
2795 valuelen++; /* returned value doesn't include room for '\0' */
2796 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2797 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2798 if (valueW && data)
2800 dlen = datalen * sizeof(WCHAR);
2801 vlen = valuelen;
2802 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2803 &dlen) == ERROR_SUCCESS) {
2804 if(data[0] && (data[1] == ':'))
2806 if((unixname = wine_get_unix_file_name(data)))
2808 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2809 HeapFree(GetProcessHeap(), 0, unixname);
2812 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2814 WCHAR pathW[MAX_PATH];
2815 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2816 BOOL added = FALSE;
2818 sprintfW(pathW, fmtW, windowsdir, data);
2819 if((unixname = wine_get_unix_file_name(pathW)))
2821 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2822 HeapFree(GetProcessHeap(), 0, unixname);
2824 if (!added)
2825 load_font_from_data_dir(data);
2827 /* reset dlen and vlen */
2828 dlen = datalen;
2829 vlen = valuelen;
2832 HeapFree(GetProcessHeap(), 0, data);
2833 HeapFree(GetProcessHeap(), 0, valueW);
2834 RegCloseKey(hkey);
2837 load_fontconfig_fonts();
2839 /* then look in any directories that we've specified in the config file */
2840 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2841 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2843 DWORD len;
2844 LPWSTR valueW;
2845 LPSTR valueA, ptr;
2847 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2849 len += sizeof(WCHAR);
2850 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2851 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2853 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2854 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2855 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2856 TRACE( "got font path %s\n", debugstr_a(valueA) );
2857 ptr = valueA;
2858 while (ptr)
2860 LPSTR next = strchr( ptr, ':' );
2861 if (next) *next++ = 0;
2862 ReadFontDir( ptr, TRUE );
2863 ptr = next;
2865 HeapFree( GetProcessHeap(), 0, valueA );
2867 HeapFree( GetProcessHeap(), 0, valueW );
2869 RegCloseKey(hkey);
2872 DumpFontList();
2873 LoadSubstList();
2874 DumpSubstList();
2875 LoadReplaceList();
2876 update_reg_entries();
2878 update_system_links();
2879 init_system_links();
2881 ReleaseMutex(font_mutex);
2882 return TRUE;
2886 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2888 TT_OS2 *pOS2;
2889 TT_HoriHeader *pHori;
2891 LONG ppem;
2893 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2894 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2896 if(height == 0) height = 16;
2898 /* Calc. height of EM square:
2900 * For +ve lfHeight we have
2901 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2902 * Re-arranging gives:
2903 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2905 * For -ve lfHeight we have
2906 * |lfHeight| = ppem
2907 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2908 * with il = winAscent + winDescent - units_per_em]
2912 if(height > 0) {
2913 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2914 ppem = MulDiv(ft_face->units_per_EM, height,
2915 pHori->Ascender - pHori->Descender);
2916 else
2917 ppem = MulDiv(ft_face->units_per_EM, height,
2918 pOS2->usWinAscent + pOS2->usWinDescent);
2920 else
2921 ppem = -height;
2923 return ppem;
2926 static struct font_mapping *map_font_file( const char *name )
2928 struct font_mapping *mapping;
2929 struct stat st;
2930 int fd;
2932 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2933 if (fstat( fd, &st ) == -1) goto error;
2935 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2937 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2939 mapping->refcount++;
2940 close( fd );
2941 return mapping;
2944 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2945 goto error;
2947 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2948 close( fd );
2950 if (mapping->data == MAP_FAILED)
2952 HeapFree( GetProcessHeap(), 0, mapping );
2953 return NULL;
2955 mapping->refcount = 1;
2956 mapping->dev = st.st_dev;
2957 mapping->ino = st.st_ino;
2958 mapping->size = st.st_size;
2959 list_add_tail( &mappings_list, &mapping->entry );
2960 return mapping;
2962 error:
2963 close( fd );
2964 return NULL;
2967 static void unmap_font_file( struct font_mapping *mapping )
2969 if (!--mapping->refcount)
2971 list_remove( &mapping->entry );
2972 munmap( mapping->data, mapping->size );
2973 HeapFree( GetProcessHeap(), 0, mapping );
2977 static LONG load_VDMX(GdiFont*, LONG);
2979 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2981 FT_Error err;
2982 FT_Face ft_face;
2983 void *data_ptr;
2984 DWORD data_size;
2986 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2988 if (face->file)
2990 if (!(font->mapping = map_font_file( face->file )))
2992 WARN("failed to map %s\n", debugstr_a(face->file));
2993 return 0;
2995 data_ptr = font->mapping->data;
2996 data_size = font->mapping->size;
2998 else
3000 data_ptr = face->font_data_ptr;
3001 data_size = face->font_data_size;
3004 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3005 if(err) {
3006 ERR("FT_New_Face rets %d\n", err);
3007 return 0;
3010 /* set it here, as load_VDMX needs it */
3011 font->ft_face = ft_face;
3013 if(FT_IS_SCALABLE(ft_face)) {
3014 /* load the VDMX table if we have one */
3015 font->ppem = load_VDMX(font, height);
3016 if(font->ppem == 0)
3017 font->ppem = calc_ppem_for_height(ft_face, height);
3018 TRACE("height %d => ppem %d\n", height, font->ppem);
3020 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3021 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3022 } else {
3023 font->ppem = height;
3024 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3025 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3027 return ft_face;
3031 static int get_nearest_charset(Face *face, int *cp)
3033 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3034 a single face with the requested charset. The idea is to check if
3035 the selected font supports the current ANSI codepage, if it does
3036 return the corresponding charset, else return the first charset */
3038 CHARSETINFO csi;
3039 int acp = GetACP(), i;
3040 DWORD fs0;
3042 *cp = acp;
3043 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3044 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3045 return csi.ciCharset;
3047 for(i = 0; i < 32; i++) {
3048 fs0 = 1L << i;
3049 if(face->fs.fsCsb[0] & fs0) {
3050 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3051 *cp = csi.ciACP;
3052 return csi.ciCharset;
3054 else
3055 FIXME("TCI failing on %x\n", fs0);
3059 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3060 face->fs.fsCsb[0], face->file);
3061 *cp = acp;
3062 return DEFAULT_CHARSET;
3065 static GdiFont *alloc_font(void)
3067 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3068 ret->gmsize = 1;
3069 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3070 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3071 ret->potm = NULL;
3072 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3073 ret->total_kern_pairs = (DWORD)-1;
3074 ret->kern_pairs = NULL;
3075 list_init(&ret->hfontlist);
3076 list_init(&ret->child_fonts);
3077 return ret;
3080 static void free_font(GdiFont *font)
3082 struct list *cursor, *cursor2;
3083 DWORD i;
3085 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3087 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3088 struct list *first_hfont;
3089 HFONTLIST *hfontlist;
3090 list_remove(cursor);
3091 if(child->font)
3093 first_hfont = list_head(&child->font->hfontlist);
3094 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3095 DeleteObject(hfontlist->hfont);
3096 HeapFree(GetProcessHeap(), 0, hfontlist);
3097 free_font(child->font);
3099 HeapFree(GetProcessHeap(), 0, child);
3102 if (font->ft_face) pFT_Done_Face(font->ft_face);
3103 if (font->mapping) unmap_font_file( font->mapping );
3104 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3105 HeapFree(GetProcessHeap(), 0, font->potm);
3106 HeapFree(GetProcessHeap(), 0, font->name);
3107 for (i = 0; i < font->gmsize; i++)
3108 HeapFree(GetProcessHeap(),0,font->gm[i]);
3109 HeapFree(GetProcessHeap(), 0, font->gm);
3110 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3111 HeapFree(GetProcessHeap(), 0, font);
3115 /*************************************************************
3116 * load_VDMX
3118 * load the vdmx entry for the specified height
3121 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3122 ( ( (FT_ULong)_x4 << 24 ) | \
3123 ( (FT_ULong)_x3 << 16 ) | \
3124 ( (FT_ULong)_x2 << 8 ) | \
3125 (FT_ULong)_x1 )
3127 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3129 typedef struct {
3130 BYTE bCharSet;
3131 BYTE xRatio;
3132 BYTE yStartRatio;
3133 BYTE yEndRatio;
3134 } Ratios;
3136 typedef struct {
3137 WORD recs;
3138 BYTE startsz;
3139 BYTE endsz;
3140 } VDMX_group;
3142 static LONG load_VDMX(GdiFont *font, LONG height)
3144 WORD hdr[3], tmp;
3145 VDMX_group group;
3146 BYTE devXRatio, devYRatio;
3147 USHORT numRecs, numRatios;
3148 DWORD result, offset = -1;
3149 LONG ppem = 0;
3150 int i;
3152 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3154 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3155 return ppem;
3157 /* FIXME: need the real device aspect ratio */
3158 devXRatio = 1;
3159 devYRatio = 1;
3161 numRecs = GET_BE_WORD(hdr[1]);
3162 numRatios = GET_BE_WORD(hdr[2]);
3164 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3165 for(i = 0; i < numRatios; i++) {
3166 Ratios ratio;
3168 offset = (3 * 2) + (i * sizeof(Ratios));
3169 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3170 offset = -1;
3172 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3174 if((ratio.xRatio == 0 &&
3175 ratio.yStartRatio == 0 &&
3176 ratio.yEndRatio == 0) ||
3177 (devXRatio == ratio.xRatio &&
3178 devYRatio >= ratio.yStartRatio &&
3179 devYRatio <= ratio.yEndRatio))
3181 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3182 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3183 offset = GET_BE_WORD(tmp);
3184 break;
3188 if(offset == -1) {
3189 FIXME("No suitable ratio found\n");
3190 return ppem;
3193 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3194 USHORT recs;
3195 BYTE startsz, endsz;
3196 WORD *vTable;
3198 recs = GET_BE_WORD(group.recs);
3199 startsz = group.startsz;
3200 endsz = group.endsz;
3202 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3204 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3205 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3206 if(result == GDI_ERROR) {
3207 FIXME("Failed to retrieve vTable\n");
3208 goto end;
3211 if(height > 0) {
3212 for(i = 0; i < recs; i++) {
3213 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3214 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3215 ppem = GET_BE_WORD(vTable[i * 3]);
3217 if(yMax + -yMin == height) {
3218 font->yMax = yMax;
3219 font->yMin = yMin;
3220 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3221 break;
3223 if(yMax + -yMin > height) {
3224 if(--i < 0) {
3225 ppem = 0;
3226 goto end; /* failed */
3228 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3229 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3230 ppem = GET_BE_WORD(vTable[i * 3]);
3231 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3232 break;
3235 if(!font->yMax) {
3236 ppem = 0;
3237 TRACE("ppem not found for height %d\n", height);
3239 } else {
3240 ppem = -height;
3241 if(ppem < startsz || ppem > endsz)
3242 goto end;
3244 for(i = 0; i < recs; i++) {
3245 USHORT yPelHeight;
3246 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3248 if(yPelHeight > ppem)
3249 break; /* failed */
3251 if(yPelHeight == ppem) {
3252 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3253 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3254 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3255 break;
3259 end:
3260 HeapFree(GetProcessHeap(), 0, vTable);
3263 return ppem;
3266 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3268 if(font->font_desc.hash != fd->hash) return TRUE;
3269 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3270 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3271 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3272 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3275 static void calc_hash(FONT_DESC *pfd)
3277 DWORD hash = 0, *ptr, two_chars;
3278 WORD *pwc;
3279 unsigned int i;
3281 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3282 hash ^= *ptr;
3283 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3284 hash ^= *ptr;
3285 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3286 two_chars = *ptr;
3287 pwc = (WCHAR *)&two_chars;
3288 if(!*pwc) break;
3289 *pwc = toupperW(*pwc);
3290 pwc++;
3291 *pwc = toupperW(*pwc);
3292 hash ^= two_chars;
3293 if(!*pwc) break;
3295 hash ^= !pfd->can_use_bitmap;
3296 pfd->hash = hash;
3297 return;
3300 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3302 GdiFont *ret;
3303 FONT_DESC fd;
3304 HFONTLIST *hflist;
3305 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3307 fd.lf = *plf;
3308 fd.matrix = *pmat;
3309 fd.can_use_bitmap = can_use_bitmap;
3310 calc_hash(&fd);
3312 /* try the child list */
3313 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3314 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3315 if(!fontcmp(ret, &fd)) {
3316 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3317 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3318 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3319 if(hflist->hfont == hfont)
3320 return ret;
3325 /* try the in-use list */
3326 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3327 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3328 if(!fontcmp(ret, &fd)) {
3329 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3330 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3331 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3332 if(hflist->hfont == hfont)
3333 return ret;
3335 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3336 hflist->hfont = hfont;
3337 list_add_head(&ret->hfontlist, &hflist->entry);
3338 return ret;
3342 /* then the unused list */
3343 font_elem_ptr = list_head(&unused_gdi_font_list);
3344 while(font_elem_ptr) {
3345 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3346 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3347 if(!fontcmp(ret, &fd)) {
3348 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3349 assert(list_empty(&ret->hfontlist));
3350 TRACE("Found %p in unused list\n", ret);
3351 list_remove(&ret->entry);
3352 list_add_head(&gdi_font_list, &ret->entry);
3353 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3354 hflist->hfont = hfont;
3355 list_add_head(&ret->hfontlist, &hflist->entry);
3356 return ret;
3359 return NULL;
3362 static void add_to_cache(GdiFont *font)
3364 static DWORD cache_num = 1;
3366 font->cache_num = cache_num++;
3367 list_add_head(&gdi_font_list, &font->entry);
3370 /*************************************************************
3371 * create_child_font_list
3373 static BOOL create_child_font_list(GdiFont *font)
3375 BOOL ret = FALSE;
3376 SYSTEM_LINKS *font_link;
3377 CHILD_FONT *font_link_entry, *new_child;
3378 FontSubst *psub;
3379 WCHAR* font_name;
3381 psub = get_font_subst(&font_subst_list, font->name, -1);
3382 font_name = psub ? psub->to.name : font->name;
3383 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3385 if(!strcmpiW(font_link->font_name, font_name))
3387 TRACE("found entry in system list\n");
3388 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3390 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3391 new_child->face = font_link_entry->face;
3392 new_child->font = NULL;
3393 list_add_tail(&font->child_fonts, &new_child->entry);
3394 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3396 ret = TRUE;
3397 break;
3401 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3402 * Sans Serif. This is how asian windows get default fallbacks for fonts
3404 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3405 font->charset != OEM_CHARSET &&
3406 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3407 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3409 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3411 TRACE("found entry in default fallback list\n");
3412 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3414 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3415 new_child->face = font_link_entry->face;
3416 new_child->font = NULL;
3417 list_add_tail(&font->child_fonts, &new_child->entry);
3418 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3420 ret = TRUE;
3421 break;
3425 return ret;
3428 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3430 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3432 if (pFT_Set_Charmap)
3434 FT_Int i;
3435 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3437 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3439 for (i = 0; i < ft_face->num_charmaps; i++)
3441 if (ft_face->charmaps[i]->encoding == encoding)
3443 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3444 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3446 switch (ft_face->charmaps[i]->platform_id)
3448 default:
3449 cmap_def = ft_face->charmaps[i];
3450 break;
3451 case 0: /* Apple Unicode */
3452 cmap0 = ft_face->charmaps[i];
3453 break;
3454 case 1: /* Macintosh */
3455 cmap1 = ft_face->charmaps[i];
3456 break;
3457 case 2: /* ISO */
3458 cmap2 = ft_face->charmaps[i];
3459 break;
3460 case 3: /* Microsoft */
3461 cmap3 = ft_face->charmaps[i];
3462 break;
3466 if (cmap3) /* prefer Microsoft cmap table */
3467 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3468 else if (cmap1)
3469 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3470 else if (cmap2)
3471 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3472 else if (cmap0)
3473 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3474 else if (cmap_def)
3475 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3477 return ft_err == FT_Err_Ok;
3480 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3483 /*************************************************************
3484 * WineEngCreateFontInstance
3487 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3489 GdiFont *ret;
3490 Face *face, *best, *best_bitmap;
3491 Family *family, *last_resort_family;
3492 struct list *family_elem_ptr, *face_elem_ptr;
3493 INT height, width = 0;
3494 unsigned int score = 0, new_score;
3495 signed int diff = 0, newdiff;
3496 BOOL bd, it, can_use_bitmap;
3497 LOGFONTW lf;
3498 CHARSETINFO csi;
3499 HFONTLIST *hflist;
3500 FMAT2 dcmat;
3501 FontSubst *psub = NULL;
3503 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3504 lf.lfWidth = abs(lf.lfWidth);
3506 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3508 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3509 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3510 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3511 lf.lfEscapement);
3513 if(dc->GraphicsMode == GM_ADVANCED)
3514 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3515 else
3517 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3518 font scaling abilities. */
3519 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3520 dcmat.eM21 = dcmat.eM12 = 0;
3523 /* Try to avoid not necessary glyph transformations */
3524 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3526 lf.lfHeight *= fabs(dcmat.eM11);
3527 lf.lfWidth *= fabs(dcmat.eM11);
3528 dcmat.eM11 = dcmat.eM22 = 1.0;
3531 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3532 dcmat.eM21, dcmat.eM22);
3534 GDI_CheckNotLock();
3535 EnterCriticalSection( &freetype_cs );
3537 /* check the cache first */
3538 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3539 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3540 LeaveCriticalSection( &freetype_cs );
3541 return ret;
3544 TRACE("not in cache\n");
3545 if(list_empty(&font_list)) /* No fonts installed */
3547 TRACE("No fonts installed\n");
3548 LeaveCriticalSection( &freetype_cs );
3549 return NULL;
3551 if(!have_installed_roman_font)
3553 TRACE("No roman font installed\n");
3554 LeaveCriticalSection( &freetype_cs );
3555 return NULL;
3558 ret = alloc_font();
3560 ret->font_desc.matrix = dcmat;
3561 ret->font_desc.lf = lf;
3562 ret->font_desc.can_use_bitmap = can_use_bitmap;
3563 calc_hash(&ret->font_desc);
3564 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3565 hflist->hfont = hfont;
3566 list_add_head(&ret->hfontlist, &hflist->entry);
3568 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3569 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3570 original value lfCharSet. Note this is a special case for
3571 Symbol and doesn't happen at least for "Wingdings*" */
3573 if(!strcmpiW(lf.lfFaceName, SymbolW))
3574 lf.lfCharSet = SYMBOL_CHARSET;
3576 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3577 switch(lf.lfCharSet) {
3578 case DEFAULT_CHARSET:
3579 csi.fs.fsCsb[0] = 0;
3580 break;
3581 default:
3582 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3583 csi.fs.fsCsb[0] = 0;
3584 break;
3588 family = NULL;
3589 if(lf.lfFaceName[0] != '\0') {
3590 SYSTEM_LINKS *font_link;
3591 CHILD_FONT *font_link_entry;
3592 LPWSTR FaceName = lf.lfFaceName;
3595 * Check for a leading '@' this signals that the font is being
3596 * requested in tategaki mode (vertical writing substitution) but
3597 * does not affect the fontface that is to be selected.
3599 if (lf.lfFaceName[0]=='@')
3600 FaceName = &lf.lfFaceName[1];
3602 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3604 if(psub) {
3605 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3606 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3607 if (psub->to.charset != -1)
3608 lf.lfCharSet = psub->to.charset;
3611 /* We want a match on name and charset or just name if
3612 charset was DEFAULT_CHARSET. If the latter then
3613 we fixup the returned charset later in get_nearest_charset
3614 where we'll either use the charset of the current ansi codepage
3615 or if that's unavailable the first charset that the font supports.
3617 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3618 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3619 if (!strcmpiW(family->FamilyName, FaceName) ||
3620 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3622 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3623 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3624 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3625 if(face->scalable || can_use_bitmap)
3626 goto found;
3632 * Try check the SystemLink list first for a replacement font.
3633 * We may find good replacements there.
3635 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3637 if(!strcmpiW(font_link->font_name, FaceName) ||
3638 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3640 TRACE("found entry in system list\n");
3641 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3643 face = font_link_entry->face;
3644 family = face->family;
3645 if(csi.fs.fsCsb[0] &
3646 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3648 if(face->scalable || can_use_bitmap)
3649 goto found;
3656 psub = NULL; /* substitution is no more relevant */
3658 /* If requested charset was DEFAULT_CHARSET then try using charset
3659 corresponding to the current ansi codepage */
3660 if (!csi.fs.fsCsb[0])
3662 INT acp = GetACP();
3663 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3664 FIXME("TCI failed on codepage %d\n", acp);
3665 csi.fs.fsCsb[0] = 0;
3666 } else
3667 lf.lfCharSet = csi.ciCharset;
3670 /* Face families are in the top 4 bits of lfPitchAndFamily,
3671 so mask with 0xF0 before testing */
3673 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3674 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3675 strcpyW(lf.lfFaceName, defFixed);
3676 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3677 strcpyW(lf.lfFaceName, defSerif);
3678 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3679 strcpyW(lf.lfFaceName, defSans);
3680 else
3681 strcpyW(lf.lfFaceName, defSans);
3682 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3683 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3684 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3685 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3686 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3687 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3688 if(face->scalable || can_use_bitmap)
3689 goto found;
3694 last_resort_family = NULL;
3695 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3696 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3697 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3698 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3699 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3700 if(face->scalable)
3701 goto found;
3702 if(can_use_bitmap && !last_resort_family)
3703 last_resort_family = family;
3708 if(last_resort_family) {
3709 family = last_resort_family;
3710 csi.fs.fsCsb[0] = 0;
3711 goto found;
3714 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3715 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3716 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3717 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3718 if(face->scalable) {
3719 csi.fs.fsCsb[0] = 0;
3720 WARN("just using first face for now\n");
3721 goto found;
3723 if(can_use_bitmap && !last_resort_family)
3724 last_resort_family = family;
3727 if(!last_resort_family) {
3728 FIXME("can't find a single appropriate font - bailing\n");
3729 free_font(ret);
3730 LeaveCriticalSection( &freetype_cs );
3731 return NULL;
3734 WARN("could only find a bitmap font - this will probably look awful!\n");
3735 family = last_resort_family;
3736 csi.fs.fsCsb[0] = 0;
3738 found:
3739 it = lf.lfItalic ? 1 : 0;
3740 bd = lf.lfWeight > 550 ? 1 : 0;
3742 height = lf.lfHeight;
3744 face = best = best_bitmap = NULL;
3745 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3747 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3749 BOOL italic, bold;
3751 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3752 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3753 new_score = (italic ^ it) + (bold ^ bd);
3754 if(!best || new_score <= score)
3756 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3757 italic, bold, it, bd);
3758 score = new_score;
3759 best = face;
3760 if(best->scalable && score == 0) break;
3761 if(!best->scalable)
3763 if(height > 0)
3764 newdiff = height - (signed int)(best->size.height);
3765 else
3766 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3767 if(!best_bitmap || new_score < score ||
3768 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3770 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3771 diff = newdiff;
3772 best_bitmap = best;
3773 if(score == 0 && diff == 0) break;
3779 if(best)
3780 face = best->scalable ? best : best_bitmap;
3781 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3782 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3784 ret->fs = face->fs;
3786 if(csi.fs.fsCsb[0]) {
3787 ret->charset = lf.lfCharSet;
3788 ret->codepage = csi.ciACP;
3790 else
3791 ret->charset = get_nearest_charset(face, &ret->codepage);
3793 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3794 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3796 ret->aveWidth = height ? lf.lfWidth : 0;
3798 if(!face->scalable) {
3799 /* Windows uses integer scaling factors for bitmap fonts */
3800 INT scale, scaled_height;
3802 /* FIXME: rotation of bitmap fonts is ignored */
3803 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3804 if (ret->aveWidth)
3805 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3806 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3808 if (height != 0) height = diff;
3809 height += face->size.height;
3811 scale = (height + face->size.height - 1) / face->size.height;
3812 scaled_height = scale * face->size.height;
3813 /* Only jump to the next height if the difference <= 25% original height */
3814 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3815 /* The jump between unscaled and doubled is delayed by 1 */
3816 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3817 ret->scale_y = scale;
3819 width = face->size.x_ppem >> 6;
3820 height = face->size.y_ppem >> 6;
3822 else
3823 ret->scale_y = 1.0;
3824 TRACE("font scale y: %f\n", ret->scale_y);
3826 ret->ft_face = OpenFontFace(ret, face, width, height);
3828 if (!ret->ft_face)
3830 free_font( ret );
3831 LeaveCriticalSection( &freetype_cs );
3832 return 0;
3835 ret->ntmFlags = face->ntmFlags;
3837 if (ret->charset == SYMBOL_CHARSET &&
3838 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3839 /* No ops */
3841 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3842 /* No ops */
3844 else {
3845 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3848 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3849 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3850 ret->underline = lf.lfUnderline ? 0xff : 0;
3851 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3852 create_child_font_list(ret);
3854 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3856 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3857 if (length != GDI_ERROR)
3859 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3860 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3861 TRACE("Loaded GSUB table of %i bytes\n",length);
3865 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3867 add_to_cache(ret);
3868 LeaveCriticalSection( &freetype_cs );
3869 return ret;
3872 static void dump_gdi_font_list(void)
3874 GdiFont *gdiFont;
3875 struct list *elem_ptr;
3877 TRACE("---------- gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3879 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3884 TRACE("---------- Unused gdiFont Cache ----------\n");
3885 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3886 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3887 TRACE("gdiFont=%p %s %d\n",
3888 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3892 /*************************************************************
3893 * WineEngDestroyFontInstance
3895 * free the gdiFont associated with this handle
3898 BOOL WineEngDestroyFontInstance(HFONT handle)
3900 GdiFont *gdiFont;
3901 HFONTLIST *hflist;
3902 BOOL ret = FALSE;
3903 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3904 int i = 0;
3906 GDI_CheckNotLock();
3907 EnterCriticalSection( &freetype_cs );
3909 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3911 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3912 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3913 if(hflist->hfont == handle)
3915 TRACE("removing child font %p from child list\n", gdiFont);
3916 list_remove(&gdiFont->entry);
3917 LeaveCriticalSection( &freetype_cs );
3918 return TRUE;
3922 TRACE("destroying hfont=%p\n", handle);
3923 if(TRACE_ON(font))
3924 dump_gdi_font_list();
3926 font_elem_ptr = list_head(&gdi_font_list);
3927 while(font_elem_ptr) {
3928 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3929 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3931 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3932 while(hfontlist_elem_ptr) {
3933 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3934 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3935 if(hflist->hfont == handle) {
3936 list_remove(&hflist->entry);
3937 HeapFree(GetProcessHeap(), 0, hflist);
3938 ret = TRUE;
3941 if(list_empty(&gdiFont->hfontlist)) {
3942 TRACE("Moving to Unused list\n");
3943 list_remove(&gdiFont->entry);
3944 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3949 font_elem_ptr = list_head(&unused_gdi_font_list);
3950 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3951 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3952 while(font_elem_ptr) {
3953 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3954 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3955 TRACE("freeing %p\n", gdiFont);
3956 list_remove(&gdiFont->entry);
3957 free_font(gdiFont);
3959 LeaveCriticalSection( &freetype_cs );
3960 return ret;
3963 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3964 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3966 GdiFont *font;
3967 LONG width, height;
3969 if (face->cached_enum_data)
3971 TRACE("Cached\n");
3972 *pelf = face->cached_enum_data->elf;
3973 *pntm = face->cached_enum_data->ntm;
3974 *ptype = face->cached_enum_data->type;
3975 return;
3978 font = alloc_font();
3980 if(face->scalable) {
3981 height = -2048; /* 2048 is the most common em size */
3982 width = 0;
3983 } else {
3984 height = face->size.y_ppem >> 6;
3985 width = face->size.x_ppem >> 6;
3987 font->scale_y = 1.0;
3989 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3991 free_font(font);
3992 return;
3995 font->name = strdupW(face->family->FamilyName);
3996 font->ntmFlags = face->ntmFlags;
3998 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4000 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4002 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4004 lstrcpynW(pelf->elfLogFont.lfFaceName,
4005 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4006 LF_FACESIZE);
4007 lstrcpynW(pelf->elfFullName,
4008 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4009 LF_FULLFACESIZE);
4010 lstrcpynW(pelf->elfStyle,
4011 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4012 LF_FACESIZE);
4014 else
4016 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4018 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4020 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4021 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4022 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4025 pntm->ntmTm.ntmFlags = face->ntmFlags;
4026 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4027 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4028 pntm->ntmFontSig = face->fs;
4030 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4032 pelf->elfLogFont.lfEscapement = 0;
4033 pelf->elfLogFont.lfOrientation = 0;
4034 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4035 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4036 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4037 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4038 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4039 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4040 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4041 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4042 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4043 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4044 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4046 *ptype = 0;
4047 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4048 *ptype |= TRUETYPE_FONTTYPE;
4049 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4050 *ptype |= DEVICE_FONTTYPE;
4051 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4052 *ptype |= RASTER_FONTTYPE;
4054 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4055 if (face->cached_enum_data)
4057 face->cached_enum_data->elf = *pelf;
4058 face->cached_enum_data->ntm = *pntm;
4059 face->cached_enum_data->type = *ptype;
4062 free_font(font);
4065 /*************************************************************
4066 * WineEngEnumFonts
4069 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4071 Family *family;
4072 Face *face;
4073 struct list *family_elem_ptr, *face_elem_ptr;
4074 ENUMLOGFONTEXW elf;
4075 NEWTEXTMETRICEXW ntm;
4076 DWORD type;
4077 FONTSIGNATURE fs;
4078 CHARSETINFO csi;
4079 LOGFONTW lf;
4080 int i;
4082 if (!plf)
4084 lf.lfCharSet = DEFAULT_CHARSET;
4085 lf.lfPitchAndFamily = 0;
4086 lf.lfFaceName[0] = 0;
4087 plf = &lf;
4090 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4092 GDI_CheckNotLock();
4093 EnterCriticalSection( &freetype_cs );
4094 if(plf->lfFaceName[0]) {
4095 FontSubst *psub;
4096 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4098 if(psub) {
4099 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4100 debugstr_w(psub->to.name));
4101 lf = *plf;
4102 strcpyW(lf.lfFaceName, psub->to.name);
4103 plf = &lf;
4106 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4107 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4108 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
4109 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4110 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4111 GetEnumStructs(face, &elf, &ntm, &type);
4112 for(i = 0; i < 32; i++) {
4113 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4114 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4115 strcpyW(elf.elfScript, OEM_DOSW);
4116 i = 32; /* break out of loop */
4117 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4118 continue;
4119 else {
4120 fs.fsCsb[0] = 1L << i;
4121 fs.fsCsb[1] = 0;
4122 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4123 TCI_SRCFONTSIG))
4124 csi.ciCharset = DEFAULT_CHARSET;
4125 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4126 if(csi.ciCharset != DEFAULT_CHARSET) {
4127 elf.elfLogFont.lfCharSet =
4128 ntm.ntmTm.tmCharSet = csi.ciCharset;
4129 if(ElfScriptsW[i])
4130 strcpyW(elf.elfScript, ElfScriptsW[i]);
4131 else
4132 FIXME("Unknown elfscript for bit %d\n", i);
4135 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4136 debugstr_w(elf.elfLogFont.lfFaceName),
4137 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4138 csi.ciCharset, type, debugstr_w(elf.elfScript),
4139 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4140 ntm.ntmTm.ntmFlags);
4141 /* release section before callback (FIXME) */
4142 LeaveCriticalSection( &freetype_cs );
4143 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4144 EnterCriticalSection( &freetype_cs );
4149 } else {
4150 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4151 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4152 face_elem_ptr = list_head(&family->faces);
4153 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4154 GetEnumStructs(face, &elf, &ntm, &type);
4155 for(i = 0; i < 32; i++) {
4156 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4157 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4158 strcpyW(elf.elfScript, OEM_DOSW);
4159 i = 32; /* break out of loop */
4160 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4161 continue;
4162 else {
4163 fs.fsCsb[0] = 1L << i;
4164 fs.fsCsb[1] = 0;
4165 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4166 TCI_SRCFONTSIG))
4167 csi.ciCharset = DEFAULT_CHARSET;
4168 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4169 if(csi.ciCharset != DEFAULT_CHARSET) {
4170 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4171 csi.ciCharset;
4172 if(ElfScriptsW[i])
4173 strcpyW(elf.elfScript, ElfScriptsW[i]);
4174 else
4175 FIXME("Unknown elfscript for bit %d\n", i);
4178 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4179 debugstr_w(elf.elfLogFont.lfFaceName),
4180 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4181 csi.ciCharset, type, debugstr_w(elf.elfScript),
4182 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4183 ntm.ntmTm.ntmFlags);
4184 /* release section before callback (FIXME) */
4185 LeaveCriticalSection( &freetype_cs );
4186 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4187 EnterCriticalSection( &freetype_cs );
4191 LeaveCriticalSection( &freetype_cs );
4192 return 1;
4195 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4197 pt->x.value = vec->x >> 6;
4198 pt->x.fract = (vec->x & 0x3f) << 10;
4199 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4200 pt->y.value = vec->y >> 6;
4201 pt->y.fract = (vec->y & 0x3f) << 10;
4202 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4203 return;
4206 /***************************************************
4207 * According to the MSDN documentation on WideCharToMultiByte,
4208 * certain codepages cannot set the default_used parameter.
4209 * This returns TRUE if the codepage can set that parameter, false else
4210 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4212 static BOOL codepage_sets_default_used(UINT codepage)
4214 switch (codepage)
4216 case CP_UTF7:
4217 case CP_UTF8:
4218 case CP_SYMBOL:
4219 return FALSE;
4220 default:
4221 return TRUE;
4226 * GSUB Table handling functions
4229 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4231 const GSUB_CoverageFormat1* cf1;
4233 cf1 = table;
4235 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4237 int count = GET_BE_WORD(cf1->GlyphCount);
4238 int i;
4239 TRACE("Coverage Format 1, %i glyphs\n",count);
4240 for (i = 0; i < count; i++)
4241 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4242 return i;
4243 return -1;
4245 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4247 const GSUB_CoverageFormat2* cf2;
4248 int i;
4249 int count;
4250 cf2 = (GSUB_CoverageFormat2*)cf1;
4252 count = GET_BE_WORD(cf2->RangeCount);
4253 TRACE("Coverage Format 2, %i ranges\n",count);
4254 for (i = 0; i < count; i++)
4256 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4257 return -1;
4258 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4259 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4261 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4262 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4265 return -1;
4267 else
4268 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4270 return -1;
4273 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4275 const GSUB_ScriptList *script;
4276 const GSUB_Script *deflt = NULL;
4277 int i;
4278 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4280 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4281 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4283 const GSUB_Script *scr;
4284 int offset;
4286 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4287 scr = (GSUB_Script*)((LPBYTE)script + offset);
4289 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4290 return scr;
4291 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4292 deflt = scr;
4294 return deflt;
4297 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4299 int i;
4300 int offset;
4301 const GSUB_LangSys *Lang;
4303 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4305 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4307 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4308 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4310 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4311 return Lang;
4313 offset = GET_BE_WORD(script->DefaultLangSys);
4314 if (offset)
4316 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4317 return Lang;
4319 return NULL;
4322 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4324 int i;
4325 const GSUB_FeatureList *feature;
4326 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4328 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4329 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4331 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4332 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4334 const GSUB_Feature *feat;
4335 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4336 return feat;
4339 return NULL;
4342 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4344 int i;
4345 int offset;
4346 const GSUB_LookupList *lookup;
4347 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4349 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4350 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4352 const GSUB_LookupTable *look;
4353 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4354 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4355 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4356 if (GET_BE_WORD(look->LookupType) != 1)
4357 FIXME("We only handle SubType 1\n");
4358 else
4360 int j;
4362 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4364 const GSUB_SingleSubstFormat1 *ssf1;
4365 offset = GET_BE_WORD(look->SubTable[j]);
4366 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4367 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4369 int offset = GET_BE_WORD(ssf1->Coverage);
4370 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4371 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4373 TRACE(" Glyph 0x%x ->",glyph);
4374 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4375 TRACE(" 0x%x\n",glyph);
4378 else
4380 const GSUB_SingleSubstFormat2 *ssf2;
4381 INT index;
4382 INT offset;
4384 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4385 offset = GET_BE_WORD(ssf1->Coverage);
4386 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4387 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4388 TRACE(" Coverage index %i\n",index);
4389 if (index != -1)
4391 TRACE(" Glyph is 0x%x ->",glyph);
4392 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4393 TRACE("0x%x\n",glyph);
4399 return glyph;
4402 static const char* get_opentype_script(const GdiFont *font)
4405 * I am not sure if this is the correct way to generate our script tag
4408 switch (font->charset)
4410 case ANSI_CHARSET: return "latn";
4411 case BALTIC_CHARSET: return "latn"; /* ?? */
4412 case CHINESEBIG5_CHARSET: return "hani";
4413 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4414 case GB2312_CHARSET: return "hani";
4415 case GREEK_CHARSET: return "grek";
4416 case HANGUL_CHARSET: return "hang";
4417 case RUSSIAN_CHARSET: return "cyrl";
4418 case SHIFTJIS_CHARSET: return "kana";
4419 case TURKISH_CHARSET: return "latn"; /* ?? */
4420 case VIETNAMESE_CHARSET: return "latn";
4421 case JOHAB_CHARSET: return "latn"; /* ?? */
4422 case ARABIC_CHARSET: return "arab";
4423 case HEBREW_CHARSET: return "hebr";
4424 case THAI_CHARSET: return "thai";
4425 default: return "latn";
4429 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4431 const GSUB_Header *header;
4432 const GSUB_Script *script;
4433 const GSUB_LangSys *language;
4434 const GSUB_Feature *feature;
4436 if (!font->GSUB_Table)
4437 return glyph;
4439 header = font->GSUB_Table;
4441 script = GSUB_get_script_table(header, get_opentype_script(font));
4442 if (!script)
4444 TRACE("Script not found\n");
4445 return glyph;
4447 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4448 if (!language)
4450 TRACE("Language not found\n");
4451 return glyph;
4453 feature = GSUB_get_feature(header, language, "vrt2");
4454 if (!feature)
4455 feature = GSUB_get_feature(header, language, "vert");
4456 if (!feature)
4458 TRACE("vrt2/vert feature not found\n");
4459 return glyph;
4461 return GSUB_apply_feature(header, feature, glyph);
4464 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4466 FT_UInt glyphId;
4468 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4469 WCHAR wc = (WCHAR)glyph;
4470 BOOL default_used;
4471 BOOL *default_used_pointer;
4472 FT_UInt ret;
4473 char buf;
4474 default_used_pointer = NULL;
4475 default_used = FALSE;
4476 if (codepage_sets_default_used(font->codepage))
4477 default_used_pointer = &default_used;
4478 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4479 ret = 0;
4480 else
4481 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4482 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4483 return get_GSUB_vert_glyph(font,ret);
4486 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4487 glyph = glyph + 0xf000;
4488 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4489 return get_GSUB_vert_glyph(font,glyphId);
4492 /*************************************************************
4493 * WineEngGetGlyphIndices
4496 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4497 LPWORD pgi, DWORD flags)
4499 int i;
4500 int default_char = -1;
4502 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4504 for(i = 0; i < count; i++)
4506 pgi[i] = get_glyph_index(font, lpstr[i]);
4507 if (pgi[i] == 0)
4509 if (default_char == -1)
4511 if (FT_IS_SFNT(font->ft_face))
4513 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4514 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4516 else
4518 TEXTMETRICW textm;
4519 WineEngGetTextMetrics(font, &textm);
4520 default_char = textm.tmDefaultChar;
4523 pgi[i] = default_char;
4526 return count;
4529 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4531 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4532 return !memcmp(matrix, &identity, sizeof(FMAT2));
4535 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4537 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4538 return !memcmp(matrix, &identity, sizeof(MAT2));
4541 /*************************************************************
4542 * WineEngGetGlyphOutline
4544 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4545 * except that the first parameter is the HWINEENGFONT of the font in
4546 * question rather than an HDC.
4549 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4550 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4551 const MAT2* lpmat)
4553 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4554 FT_Face ft_face = incoming_font->ft_face;
4555 GdiFont *font = incoming_font;
4556 FT_UInt glyph_index;
4557 DWORD width, height, pitch, needed = 0;
4558 FT_Bitmap ft_bitmap;
4559 FT_Error err;
4560 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4561 FT_Angle angle = 0;
4562 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4563 double widthRatio = 1.0;
4564 FT_Matrix transMat = identityMat;
4565 FT_Matrix transMatUnrotated;
4566 BOOL needsTransform = FALSE;
4567 BOOL tategaki = (font->GSUB_Table != NULL);
4568 UINT original_index;
4570 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4571 buflen, buf, lpmat);
4573 TRACE("font transform %f %f %f %f\n",
4574 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4575 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4577 GDI_CheckNotLock();
4578 EnterCriticalSection( &freetype_cs );
4580 if(format & GGO_GLYPH_INDEX) {
4581 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4582 original_index = glyph;
4583 format &= ~GGO_GLYPH_INDEX;
4584 } else {
4585 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4586 ft_face = font->ft_face;
4587 original_index = glyph_index;
4590 if(format & GGO_UNHINTED) {
4591 load_flags |= FT_LOAD_NO_HINTING;
4592 format &= ~GGO_UNHINTED;
4595 /* tategaki never appears to happen to lower glyph index */
4596 if (glyph_index < TATEGAKI_LOWER_BOUND )
4597 tategaki = FALSE;
4599 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4600 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4601 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4602 font->gmsize * sizeof(GM*));
4603 } else {
4604 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4605 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4607 *lpgm = FONT_GM(font,original_index)->gm;
4608 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4609 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4610 lpgm->gmCellIncX, lpgm->gmCellIncY);
4611 LeaveCriticalSection( &freetype_cs );
4612 return 1; /* FIXME */
4616 if (!font->gm[original_index / GM_BLOCK_SIZE])
4617 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4619 /* Scaling factor */
4620 if (font->aveWidth)
4622 TEXTMETRICW tm;
4624 WineEngGetTextMetrics(font, &tm);
4626 widthRatio = (double)font->aveWidth;
4627 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4629 else
4630 widthRatio = font->scale_y;
4632 /* Scaling transform */
4633 if (widthRatio != 1.0 || font->scale_y != 1.0)
4635 FT_Matrix scaleMat;
4636 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4637 scaleMat.xy = 0;
4638 scaleMat.yx = 0;
4639 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4641 pFT_Matrix_Multiply(&scaleMat, &transMat);
4642 needsTransform = TRUE;
4645 /* Slant transform */
4646 if (font->fake_italic) {
4647 FT_Matrix slantMat;
4649 slantMat.xx = (1 << 16);
4650 slantMat.xy = ((1 << 16) >> 2);
4651 slantMat.yx = 0;
4652 slantMat.yy = (1 << 16);
4653 pFT_Matrix_Multiply(&slantMat, &transMat);
4654 needsTransform = TRUE;
4657 /* Rotation transform */
4658 transMatUnrotated = transMat;
4659 if(font->orientation && !tategaki) {
4660 FT_Matrix rotationMat;
4661 FT_Vector vecAngle;
4662 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4663 pFT_Vector_Unit(&vecAngle, angle);
4664 rotationMat.xx = vecAngle.x;
4665 rotationMat.xy = -vecAngle.y;
4666 rotationMat.yx = -rotationMat.xy;
4667 rotationMat.yy = rotationMat.xx;
4669 pFT_Matrix_Multiply(&rotationMat, &transMat);
4670 needsTransform = TRUE;
4673 /* World transform */
4674 if (!is_identity_FMAT2(&font->font_desc.matrix))
4676 FT_Matrix worldMat;
4677 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4678 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4679 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4680 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4681 pFT_Matrix_Multiply(&worldMat, &transMat);
4682 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4683 needsTransform = TRUE;
4686 /* Extra transformation specified by caller */
4687 if (!is_identity_MAT2(lpmat))
4689 FT_Matrix extraMat;
4690 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4691 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4692 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4693 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4694 pFT_Matrix_Multiply(&extraMat, &transMat);
4695 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4696 needsTransform = TRUE;
4699 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4700 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4701 format == GGO_GRAY8_BITMAP))
4703 load_flags |= FT_LOAD_NO_BITMAP;
4706 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4708 if(err) {
4709 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4710 LeaveCriticalSection( &freetype_cs );
4711 return GDI_ERROR;
4714 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4715 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4717 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4718 lsb = left >> 6;
4719 bbx = (right - left) >> 6;
4721 if(!needsTransform) {
4722 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4723 bottom = (ft_face->glyph->metrics.horiBearingY -
4724 ft_face->glyph->metrics.height) & -64;
4725 lpgm->gmCellIncX = adv;
4726 lpgm->gmCellIncY = 0;
4727 } else {
4728 INT xc, yc;
4729 FT_Vector vec;
4730 for(xc = 0; xc < 2; xc++) {
4731 for(yc = 0; yc < 2; yc++) {
4732 vec.x = (ft_face->glyph->metrics.horiBearingX +
4733 xc * ft_face->glyph->metrics.width);
4734 vec.y = ft_face->glyph->metrics.horiBearingY -
4735 yc * ft_face->glyph->metrics.height;
4736 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4737 pFT_Vector_Transform(&vec, &transMat);
4738 if(xc == 0 && yc == 0) {
4739 left = right = vec.x;
4740 top = bottom = vec.y;
4741 } else {
4742 if(vec.x < left) left = vec.x;
4743 else if(vec.x > right) right = vec.x;
4744 if(vec.y < bottom) bottom = vec.y;
4745 else if(vec.y > top) top = vec.y;
4749 left = left & -64;
4750 right = (right + 63) & -64;
4751 bottom = bottom & -64;
4752 top = (top + 63) & -64;
4754 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4755 vec.x = ft_face->glyph->metrics.horiAdvance;
4756 vec.y = 0;
4757 pFT_Vector_Transform(&vec, &transMat);
4758 lpgm->gmCellIncX = (vec.x+63) >> 6;
4759 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4761 vec.x = ft_face->glyph->metrics.horiAdvance;
4762 vec.y = 0;
4763 pFT_Vector_Transform(&vec, &transMatUnrotated);
4764 adv = (vec.x+63) >> 6;
4766 lpgm->gmBlackBoxX = (right - left) >> 6;
4767 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4768 lpgm->gmptGlyphOrigin.x = left >> 6;
4769 lpgm->gmptGlyphOrigin.y = top >> 6;
4771 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4772 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4773 lpgm->gmCellIncX, lpgm->gmCellIncY);
4775 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4776 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4778 FONT_GM(font,original_index)->gm = *lpgm;
4779 FONT_GM(font,original_index)->adv = adv;
4780 FONT_GM(font,original_index)->lsb = lsb;
4781 FONT_GM(font,original_index)->bbx = bbx;
4782 FONT_GM(font,original_index)->init = TRUE;
4785 if(format == GGO_METRICS)
4787 LeaveCriticalSection( &freetype_cs );
4788 return 1; /* FIXME */
4791 if(ft_face->glyph->format != ft_glyph_format_outline &&
4792 (format == GGO_NATIVE || format == GGO_BEZIER ||
4793 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4794 format == GGO_GRAY8_BITMAP))
4796 TRACE("loaded a bitmap\n");
4797 LeaveCriticalSection( &freetype_cs );
4798 return GDI_ERROR;
4801 switch(format) {
4802 case GGO_BITMAP:
4803 width = lpgm->gmBlackBoxX;
4804 height = lpgm->gmBlackBoxY;
4805 pitch = ((width + 31) >> 5) << 2;
4806 needed = pitch * height;
4808 if(!buf || !buflen) break;
4810 switch(ft_face->glyph->format) {
4811 case ft_glyph_format_bitmap:
4813 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4814 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4815 INT h = ft_face->glyph->bitmap.rows;
4816 while(h--) {
4817 memcpy(dst, src, w);
4818 src += ft_face->glyph->bitmap.pitch;
4819 dst += pitch;
4821 break;
4824 case ft_glyph_format_outline:
4825 ft_bitmap.width = width;
4826 ft_bitmap.rows = height;
4827 ft_bitmap.pitch = pitch;
4828 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4829 ft_bitmap.buffer = buf;
4831 if(needsTransform)
4832 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4834 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4836 /* Note: FreeType will only set 'black' bits for us. */
4837 memset(buf, 0, needed);
4838 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4839 break;
4841 default:
4842 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4843 LeaveCriticalSection( &freetype_cs );
4844 return GDI_ERROR;
4846 break;
4848 case GGO_GRAY2_BITMAP:
4849 case GGO_GRAY4_BITMAP:
4850 case GGO_GRAY8_BITMAP:
4851 case WINE_GGO_GRAY16_BITMAP:
4853 unsigned int mult, row, col;
4854 BYTE *start, *ptr;
4856 width = lpgm->gmBlackBoxX;
4857 height = lpgm->gmBlackBoxY;
4858 pitch = (width + 3) / 4 * 4;
4859 needed = pitch * height;
4861 if(!buf || !buflen) break;
4863 switch(ft_face->glyph->format) {
4864 case ft_glyph_format_bitmap:
4866 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4867 INT h = ft_face->glyph->bitmap.rows;
4868 INT x;
4869 while(h--) {
4870 for(x = 0; x < pitch; x++)
4872 if(x < ft_face->glyph->bitmap.width)
4873 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4874 else
4875 dst[x] = 0;
4877 src += ft_face->glyph->bitmap.pitch;
4878 dst += pitch;
4880 LeaveCriticalSection( &freetype_cs );
4881 return needed;
4883 case ft_glyph_format_outline:
4885 ft_bitmap.width = width;
4886 ft_bitmap.rows = height;
4887 ft_bitmap.pitch = pitch;
4888 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4889 ft_bitmap.buffer = buf;
4891 if(needsTransform)
4892 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4894 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4896 memset(ft_bitmap.buffer, 0, buflen);
4898 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4900 if(format == GGO_GRAY2_BITMAP)
4901 mult = 4;
4902 else if(format == GGO_GRAY4_BITMAP)
4903 mult = 16;
4904 else if(format == GGO_GRAY8_BITMAP)
4905 mult = 64;
4906 else /* format == WINE_GGO_GRAY16_BITMAP */
4908 LeaveCriticalSection( &freetype_cs );
4909 return needed;
4911 break;
4913 default:
4914 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4915 LeaveCriticalSection( &freetype_cs );
4916 return GDI_ERROR;
4919 start = buf;
4920 for(row = 0; row < height; row++) {
4921 ptr = start;
4922 for(col = 0; col < width; col++, ptr++) {
4923 *ptr = (((int)*ptr) * mult + 128) / 256;
4925 start += pitch;
4927 break;
4930 case WINE_GGO_HRGB_BITMAP:
4931 case WINE_GGO_HBGR_BITMAP:
4932 case WINE_GGO_VRGB_BITMAP:
4933 case WINE_GGO_VBGR_BITMAP:
4934 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4936 switch (ft_face->glyph->format)
4938 case FT_GLYPH_FORMAT_BITMAP:
4940 BYTE *src, *dst;
4941 INT src_pitch, x;
4943 width = lpgm->gmBlackBoxX;
4944 height = lpgm->gmBlackBoxY;
4945 pitch = width * 4;
4946 needed = pitch * height;
4948 if (!buf || !buflen) break;
4950 memset(buf, 0, buflen);
4951 dst = buf;
4952 src = ft_face->glyph->bitmap.buffer;
4953 src_pitch = ft_face->glyph->bitmap.pitch;
4955 while ( height-- )
4957 for (x = 0; x < width; x++)
4959 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4960 ((unsigned int *)dst)[x] = ~0u;
4962 src += src_pitch;
4963 dst += pitch;
4966 break;
4969 case FT_GLYPH_FORMAT_OUTLINE:
4971 unsigned int *dst;
4972 BYTE *src;
4973 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4974 INT x_shift, y_shift;
4975 BOOL rgb;
4976 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4977 FT_Render_Mode render_mode =
4978 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4979 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4981 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4983 if ( render_mode == FT_RENDER_MODE_LCD)
4985 lpgm->gmBlackBoxX += 2;
4986 lpgm->gmptGlyphOrigin.x -= 1;
4988 else
4990 lpgm->gmBlackBoxY += 2;
4991 lpgm->gmptGlyphOrigin.y += 1;
4995 width = lpgm->gmBlackBoxX;
4996 height = lpgm->gmBlackBoxY;
4997 pitch = width * 4;
4998 needed = pitch * height;
5000 if (!buf || !buflen) break;
5002 memset(buf, 0, buflen);
5003 dst = buf;
5004 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5006 if ( needsTransform )
5007 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5009 if ( pFT_Library_SetLcdFilter )
5010 pFT_Library_SetLcdFilter( library, lcdfilter );
5011 pFT_Render_Glyph (ft_face->glyph, render_mode);
5013 src = ft_face->glyph->bitmap.buffer;
5014 src_pitch = ft_face->glyph->bitmap.pitch;
5015 src_width = ft_face->glyph->bitmap.width;
5016 src_height = ft_face->glyph->bitmap.rows;
5018 if ( render_mode == FT_RENDER_MODE_LCD)
5020 rgb_interval = 1;
5021 hmul = 3;
5022 vmul = 1;
5024 else
5026 rgb_interval = src_pitch;
5027 hmul = 1;
5028 vmul = 3;
5031 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5032 if ( x_shift < 0 ) x_shift = 0;
5033 if ( x_shift + (src_width / hmul) > width )
5034 x_shift = width - (src_width / hmul);
5036 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5037 if ( y_shift < 0 ) y_shift = 0;
5038 if ( y_shift + (src_height / vmul) > height )
5039 y_shift = height - (src_height / vmul);
5041 dst += x_shift + y_shift * ( pitch / 4 );
5042 while ( src_height )
5044 for ( x = 0; x < src_width / hmul; x++ )
5046 if ( rgb )
5048 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5049 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5050 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5051 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5053 else
5055 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5056 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5057 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5058 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5061 src += src_pitch * vmul;
5062 dst += pitch / 4;
5063 src_height -= vmul;
5066 break;
5069 default:
5070 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5071 LeaveCriticalSection ( &freetype_cs );
5072 return GDI_ERROR;
5075 break;
5077 #else
5078 LeaveCriticalSection( &freetype_cs );
5079 return GDI_ERROR;
5080 #endif
5082 case GGO_NATIVE:
5084 int contour, point = 0, first_pt;
5085 FT_Outline *outline = &ft_face->glyph->outline;
5086 TTPOLYGONHEADER *pph;
5087 TTPOLYCURVE *ppc;
5088 DWORD pph_start, cpfx, type;
5090 if(buflen == 0) buf = NULL;
5092 if (needsTransform && buf) {
5093 pFT_Outline_Transform(outline, &transMat);
5096 for(contour = 0; contour < outline->n_contours; contour++) {
5097 pph_start = needed;
5098 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5099 first_pt = point;
5100 if(buf) {
5101 pph->dwType = TT_POLYGON_TYPE;
5102 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5104 needed += sizeof(*pph);
5105 point++;
5106 while(point <= outline->contours[contour]) {
5107 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5108 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5109 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5110 cpfx = 0;
5111 do {
5112 if(buf)
5113 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5114 cpfx++;
5115 point++;
5116 } while(point <= outline->contours[contour] &&
5117 (outline->tags[point] & FT_Curve_Tag_On) ==
5118 (outline->tags[point-1] & FT_Curve_Tag_On));
5119 /* At the end of a contour Windows adds the start point, but
5120 only for Beziers */
5121 if(point > outline->contours[contour] &&
5122 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5123 if(buf)
5124 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5125 cpfx++;
5126 } else if(point <= outline->contours[contour] &&
5127 outline->tags[point] & FT_Curve_Tag_On) {
5128 /* add closing pt for bezier */
5129 if(buf)
5130 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5131 cpfx++;
5132 point++;
5134 if(buf) {
5135 ppc->wType = type;
5136 ppc->cpfx = cpfx;
5138 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5140 if(buf)
5141 pph->cb = needed - pph_start;
5143 break;
5145 case GGO_BEZIER:
5147 /* Convert the quadratic Beziers to cubic Beziers.
5148 The parametric eqn for a cubic Bezier is, from PLRM:
5149 r(t) = at^3 + bt^2 + ct + r0
5150 with the control points:
5151 r1 = r0 + c/3
5152 r2 = r1 + (c + b)/3
5153 r3 = r0 + c + b + a
5155 A quadratic Beizer has the form:
5156 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5158 So equating powers of t leads to:
5159 r1 = 2/3 p1 + 1/3 p0
5160 r2 = 2/3 p1 + 1/3 p2
5161 and of course r0 = p0, r3 = p2
5164 int contour, point = 0, first_pt;
5165 FT_Outline *outline = &ft_face->glyph->outline;
5166 TTPOLYGONHEADER *pph;
5167 TTPOLYCURVE *ppc;
5168 DWORD pph_start, cpfx, type;
5169 FT_Vector cubic_control[4];
5170 if(buflen == 0) buf = NULL;
5172 if (needsTransform && buf) {
5173 pFT_Outline_Transform(outline, &transMat);
5176 for(contour = 0; contour < outline->n_contours; contour++) {
5177 pph_start = needed;
5178 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5179 first_pt = point;
5180 if(buf) {
5181 pph->dwType = TT_POLYGON_TYPE;
5182 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5184 needed += sizeof(*pph);
5185 point++;
5186 while(point <= outline->contours[contour]) {
5187 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5188 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5189 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5190 cpfx = 0;
5191 do {
5192 if(type == TT_PRIM_LINE) {
5193 if(buf)
5194 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5195 cpfx++;
5196 point++;
5197 } else {
5198 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5199 so cpfx = 3n */
5201 /* FIXME: Possible optimization in endpoint calculation
5202 if there are two consecutive curves */
5203 cubic_control[0] = outline->points[point-1];
5204 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5205 cubic_control[0].x += outline->points[point].x + 1;
5206 cubic_control[0].y += outline->points[point].y + 1;
5207 cubic_control[0].x >>= 1;
5208 cubic_control[0].y >>= 1;
5210 if(point+1 > outline->contours[contour])
5211 cubic_control[3] = outline->points[first_pt];
5212 else {
5213 cubic_control[3] = outline->points[point+1];
5214 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5215 cubic_control[3].x += outline->points[point].x + 1;
5216 cubic_control[3].y += outline->points[point].y + 1;
5217 cubic_control[3].x >>= 1;
5218 cubic_control[3].y >>= 1;
5221 /* r1 = 1/3 p0 + 2/3 p1
5222 r2 = 1/3 p2 + 2/3 p1 */
5223 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5224 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5225 cubic_control[2] = cubic_control[1];
5226 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5227 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5228 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5229 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5230 if(buf) {
5231 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5232 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5233 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5235 cpfx += 3;
5236 point++;
5238 } while(point <= outline->contours[contour] &&
5239 (outline->tags[point] & FT_Curve_Tag_On) ==
5240 (outline->tags[point-1] & FT_Curve_Tag_On));
5241 /* At the end of a contour Windows adds the start point,
5242 but only for Beziers and we've already done that.
5244 if(point <= outline->contours[contour] &&
5245 outline->tags[point] & FT_Curve_Tag_On) {
5246 /* This is the closing pt of a bezier, but we've already
5247 added it, so just inc point and carry on */
5248 point++;
5250 if(buf) {
5251 ppc->wType = type;
5252 ppc->cpfx = cpfx;
5254 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5256 if(buf)
5257 pph->cb = needed - pph_start;
5259 break;
5262 default:
5263 FIXME("Unsupported format %d\n", format);
5264 LeaveCriticalSection( &freetype_cs );
5265 return GDI_ERROR;
5267 LeaveCriticalSection( &freetype_cs );
5268 return needed;
5271 static BOOL get_bitmap_text_metrics(GdiFont *font)
5273 FT_Face ft_face = font->ft_face;
5274 #ifdef HAVE_FREETYPE_FTWINFNT_H
5275 FT_WinFNT_HeaderRec winfnt_header;
5276 #endif
5277 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5278 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5279 font->potm->otmSize = size;
5281 #define TM font->potm->otmTextMetrics
5282 #ifdef HAVE_FREETYPE_FTWINFNT_H
5283 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5285 TM.tmHeight = winfnt_header.pixel_height;
5286 TM.tmAscent = winfnt_header.ascent;
5287 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5288 TM.tmInternalLeading = winfnt_header.internal_leading;
5289 TM.tmExternalLeading = winfnt_header.external_leading;
5290 TM.tmAveCharWidth = winfnt_header.avg_width;
5291 TM.tmMaxCharWidth = winfnt_header.max_width;
5292 TM.tmWeight = winfnt_header.weight;
5293 TM.tmOverhang = 0;
5294 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5295 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5296 TM.tmFirstChar = winfnt_header.first_char;
5297 TM.tmLastChar = winfnt_header.last_char;
5298 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5299 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5300 TM.tmItalic = winfnt_header.italic;
5301 TM.tmUnderlined = font->underline;
5302 TM.tmStruckOut = font->strikeout;
5303 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5304 TM.tmCharSet = winfnt_header.charset;
5306 else
5307 #endif
5309 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5310 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5311 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5312 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5313 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5314 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5315 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5316 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5317 TM.tmOverhang = 0;
5318 TM.tmDigitizedAspectX = 96; /* FIXME */
5319 TM.tmDigitizedAspectY = 96; /* FIXME */
5320 TM.tmFirstChar = 1;
5321 TM.tmLastChar = 255;
5322 TM.tmDefaultChar = 32;
5323 TM.tmBreakChar = 32;
5324 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5325 TM.tmUnderlined = font->underline;
5326 TM.tmStruckOut = font->strikeout;
5327 /* NB inverted meaning of TMPF_FIXED_PITCH */
5328 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5329 TM.tmCharSet = font->charset;
5331 #undef TM
5333 return TRUE;
5337 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5339 double scale_x, scale_y;
5341 if (font->aveWidth)
5343 scale_x = (double)font->aveWidth;
5344 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5346 else
5347 scale_x = font->scale_y;
5349 scale_x *= fabs(font->font_desc.matrix.eM11);
5350 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5352 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5353 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5355 SCALE_Y(ptm->tmHeight);
5356 SCALE_Y(ptm->tmAscent);
5357 SCALE_Y(ptm->tmDescent);
5358 SCALE_Y(ptm->tmInternalLeading);
5359 SCALE_Y(ptm->tmExternalLeading);
5360 SCALE_Y(ptm->tmOverhang);
5362 SCALE_X(ptm->tmAveCharWidth);
5363 SCALE_X(ptm->tmMaxCharWidth);
5365 #undef SCALE_X
5366 #undef SCALE_Y
5369 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5371 double scale_x, scale_y;
5373 if (font->aveWidth)
5375 scale_x = (double)font->aveWidth;
5376 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5378 else
5379 scale_x = font->scale_y;
5381 scale_x *= fabs(font->font_desc.matrix.eM11);
5382 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5384 scale_font_metrics(font, &potm->otmTextMetrics);
5386 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5387 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5389 SCALE_Y(potm->otmAscent);
5390 SCALE_Y(potm->otmDescent);
5391 SCALE_Y(potm->otmLineGap);
5392 SCALE_Y(potm->otmsCapEmHeight);
5393 SCALE_Y(potm->otmsXHeight);
5394 SCALE_Y(potm->otmrcFontBox.top);
5395 SCALE_Y(potm->otmrcFontBox.bottom);
5396 SCALE_X(potm->otmrcFontBox.left);
5397 SCALE_X(potm->otmrcFontBox.right);
5398 SCALE_Y(potm->otmMacAscent);
5399 SCALE_Y(potm->otmMacDescent);
5400 SCALE_Y(potm->otmMacLineGap);
5401 SCALE_X(potm->otmptSubscriptSize.x);
5402 SCALE_Y(potm->otmptSubscriptSize.y);
5403 SCALE_X(potm->otmptSubscriptOffset.x);
5404 SCALE_Y(potm->otmptSubscriptOffset.y);
5405 SCALE_X(potm->otmptSuperscriptSize.x);
5406 SCALE_Y(potm->otmptSuperscriptSize.y);
5407 SCALE_X(potm->otmptSuperscriptOffset.x);
5408 SCALE_Y(potm->otmptSuperscriptOffset.y);
5409 SCALE_Y(potm->otmsStrikeoutSize);
5410 SCALE_Y(potm->otmsStrikeoutPosition);
5411 SCALE_Y(potm->otmsUnderscoreSize);
5412 SCALE_Y(potm->otmsUnderscorePosition);
5414 #undef SCALE_X
5415 #undef SCALE_Y
5418 /*************************************************************
5419 * WineEngGetTextMetrics
5422 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5424 GDI_CheckNotLock();
5425 EnterCriticalSection( &freetype_cs );
5426 if(!font->potm) {
5427 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5428 if(!get_bitmap_text_metrics(font))
5430 LeaveCriticalSection( &freetype_cs );
5431 return FALSE;
5434 if(!font->potm)
5436 LeaveCriticalSection( &freetype_cs );
5437 return FALSE;
5439 *ptm = font->potm->otmTextMetrics;
5440 scale_font_metrics(font, ptm);
5441 LeaveCriticalSection( &freetype_cs );
5442 return TRUE;
5445 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5447 int i;
5449 for(i = 0; i < ft_face->num_charmaps; i++)
5451 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5452 return TRUE;
5454 return FALSE;
5457 /*************************************************************
5458 * WineEngGetOutlineTextMetrics
5461 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5462 OUTLINETEXTMETRICW *potm)
5464 FT_Face ft_face = font->ft_face;
5465 UINT needed, lenfam, lensty, ret;
5466 TT_OS2 *pOS2;
5467 TT_HoriHeader *pHori;
5468 TT_Postscript *pPost;
5469 FT_Fixed x_scale, y_scale;
5470 WCHAR *family_nameW, *style_nameW;
5471 static const WCHAR spaceW[] = {' ', '\0'};
5472 char *cp;
5473 INT ascent, descent;
5475 TRACE("font=%p\n", font);
5477 if(!FT_IS_SCALABLE(ft_face))
5478 return 0;
5480 GDI_CheckNotLock();
5481 EnterCriticalSection( &freetype_cs );
5483 if(font->potm) {
5484 if(cbSize >= font->potm->otmSize)
5486 memcpy(potm, font->potm, font->potm->otmSize);
5487 scale_outline_font_metrics(font, potm);
5489 LeaveCriticalSection( &freetype_cs );
5490 return font->potm->otmSize;
5494 needed = sizeof(*potm);
5496 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5497 family_nameW = strdupW(font->name);
5499 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5500 * sizeof(WCHAR);
5501 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5502 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5503 style_nameW, lensty/sizeof(WCHAR));
5505 /* These names should be read from the TT name table */
5507 /* length of otmpFamilyName */
5508 needed += lenfam;
5510 /* length of otmpFaceName */
5511 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5512 needed += lenfam; /* just the family name */
5513 } else {
5514 needed += lenfam + lensty; /* family + " " + style */
5517 /* length of otmpStyleName */
5518 needed += lensty;
5520 /* length of otmpFullName */
5521 needed += lenfam + lensty;
5524 x_scale = ft_face->size->metrics.x_scale;
5525 y_scale = ft_face->size->metrics.y_scale;
5527 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5528 if(!pOS2) {
5529 FIXME("Can't find OS/2 table - not TT font?\n");
5530 ret = 0;
5531 goto end;
5534 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5535 if(!pHori) {
5536 FIXME("Can't find HHEA table - not TT font?\n");
5537 ret = 0;
5538 goto end;
5541 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5543 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",
5544 pOS2->usWinAscent, pOS2->usWinDescent,
5545 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5546 ft_face->ascender, ft_face->descender, ft_face->height,
5547 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5548 ft_face->bbox.yMax, ft_face->bbox.yMin);
5550 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5551 font->potm->otmSize = needed;
5553 #define TM font->potm->otmTextMetrics
5555 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5556 ascent = pHori->Ascender;
5557 descent = -pHori->Descender;
5558 } else {
5559 ascent = pOS2->usWinAscent;
5560 descent = pOS2->usWinDescent;
5563 if(font->yMax) {
5564 TM.tmAscent = font->yMax;
5565 TM.tmDescent = -font->yMin;
5566 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5567 } else {
5568 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5569 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5570 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5571 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5574 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5576 /* MSDN says:
5577 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5579 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5580 ((ascent + descent) -
5581 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5583 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5584 if (TM.tmAveCharWidth == 0) {
5585 TM.tmAveCharWidth = 1;
5587 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5588 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5589 TM.tmOverhang = 0;
5590 TM.tmDigitizedAspectX = 300;
5591 TM.tmDigitizedAspectY = 300;
5592 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5593 * symbol range to 0 - f0ff
5596 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5598 TM.tmFirstChar = 0;
5599 switch(GetACP())
5601 case 1257: /* Baltic */
5602 TM.tmLastChar = 0xf8fd;
5603 break;
5604 default:
5605 TM.tmLastChar = 0xf0ff;
5607 TM.tmBreakChar = 0x20;
5608 TM.tmDefaultChar = 0x1f;
5610 else
5612 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5613 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5615 if(pOS2->usFirstCharIndex <= 1)
5616 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5617 else if (pOS2->usFirstCharIndex > 0xff)
5618 TM.tmBreakChar = 0x20;
5619 else
5620 TM.tmBreakChar = pOS2->usFirstCharIndex;
5621 TM.tmDefaultChar = TM.tmBreakChar - 1;
5623 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5624 TM.tmUnderlined = font->underline;
5625 TM.tmStruckOut = font->strikeout;
5627 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5628 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5629 (pOS2->version == 0xFFFFU ||
5630 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5631 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5632 else
5633 TM.tmPitchAndFamily = 0;
5635 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5637 case PAN_FAMILY_SCRIPT:
5638 TM.tmPitchAndFamily |= FF_SCRIPT;
5639 break;
5641 case PAN_FAMILY_DECORATIVE:
5642 TM.tmPitchAndFamily |= FF_DECORATIVE;
5643 break;
5645 case PAN_ANY:
5646 case PAN_NO_FIT:
5647 case PAN_FAMILY_TEXT_DISPLAY:
5648 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5649 /* which is clearly not what the panose spec says. */
5650 default:
5651 if(TM.tmPitchAndFamily == 0 || /* fixed */
5652 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5653 TM.tmPitchAndFamily = FF_MODERN;
5654 else
5656 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5658 case PAN_ANY:
5659 case PAN_NO_FIT:
5660 default:
5661 TM.tmPitchAndFamily |= FF_DONTCARE;
5662 break;
5664 case PAN_SERIF_COVE:
5665 case PAN_SERIF_OBTUSE_COVE:
5666 case PAN_SERIF_SQUARE_COVE:
5667 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5668 case PAN_SERIF_SQUARE:
5669 case PAN_SERIF_THIN:
5670 case PAN_SERIF_BONE:
5671 case PAN_SERIF_EXAGGERATED:
5672 case PAN_SERIF_TRIANGLE:
5673 TM.tmPitchAndFamily |= FF_ROMAN;
5674 break;
5676 case PAN_SERIF_NORMAL_SANS:
5677 case PAN_SERIF_OBTUSE_SANS:
5678 case PAN_SERIF_PERP_SANS:
5679 case PAN_SERIF_FLARED:
5680 case PAN_SERIF_ROUNDED:
5681 TM.tmPitchAndFamily |= FF_SWISS;
5682 break;
5685 break;
5688 if(FT_IS_SCALABLE(ft_face))
5689 TM.tmPitchAndFamily |= TMPF_VECTOR;
5691 if(FT_IS_SFNT(ft_face))
5693 if (font->ntmFlags & NTM_PS_OPENTYPE)
5694 TM.tmPitchAndFamily |= TMPF_DEVICE;
5695 else
5696 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5699 TM.tmCharSet = font->charset;
5701 font->potm->otmFiller = 0;
5702 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5703 font->potm->otmfsSelection = pOS2->fsSelection;
5704 font->potm->otmfsType = pOS2->fsType;
5705 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5706 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5707 font->potm->otmItalicAngle = 0; /* POST table */
5708 font->potm->otmEMSquare = ft_face->units_per_EM;
5709 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5710 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5711 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5712 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5713 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5714 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5715 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5716 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5717 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5718 font->potm->otmMacAscent = TM.tmAscent;
5719 font->potm->otmMacDescent = -TM.tmDescent;
5720 font->potm->otmMacLineGap = font->potm->otmLineGap;
5721 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5722 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5723 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5724 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5725 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5726 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5727 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5728 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5729 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5730 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5731 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5732 if(!pPost) {
5733 font->potm->otmsUnderscoreSize = 0;
5734 font->potm->otmsUnderscorePosition = 0;
5735 } else {
5736 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5737 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5739 #undef TM
5741 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5742 cp = (char*)font->potm + sizeof(*font->potm);
5743 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5744 strcpyW((WCHAR*)cp, family_nameW);
5745 cp += lenfam;
5746 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5747 strcpyW((WCHAR*)cp, style_nameW);
5748 cp += lensty;
5749 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5750 strcpyW((WCHAR*)cp, family_nameW);
5751 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5752 strcatW((WCHAR*)cp, spaceW);
5753 strcatW((WCHAR*)cp, style_nameW);
5754 cp += lenfam + lensty;
5755 } else
5756 cp += lenfam;
5757 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5758 strcpyW((WCHAR*)cp, family_nameW);
5759 strcatW((WCHAR*)cp, spaceW);
5760 strcatW((WCHAR*)cp, style_nameW);
5761 ret = needed;
5763 if(potm && needed <= cbSize)
5765 memcpy(potm, font->potm, font->potm->otmSize);
5766 scale_outline_font_metrics(font, potm);
5769 end:
5770 HeapFree(GetProcessHeap(), 0, style_nameW);
5771 HeapFree(GetProcessHeap(), 0, family_nameW);
5773 LeaveCriticalSection( &freetype_cs );
5774 return ret;
5777 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5779 HFONTLIST *hfontlist;
5780 child->font = alloc_font();
5781 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5782 if(!child->font->ft_face)
5784 free_font(child->font);
5785 child->font = NULL;
5786 return FALSE;
5789 child->font->font_desc = font->font_desc;
5790 child->font->ntmFlags = child->face->ntmFlags;
5791 child->font->orientation = font->orientation;
5792 child->font->scale_y = font->scale_y;
5793 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5794 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5795 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5796 child->font->base_font = font;
5797 list_add_head(&child_font_list, &child->font->entry);
5798 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5799 return TRUE;
5802 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5804 FT_UInt g;
5805 CHILD_FONT *child_font;
5807 if(font->base_font)
5808 font = font->base_font;
5810 *linked_font = font;
5812 if((*glyph = get_glyph_index(font, c)))
5813 return TRUE;
5815 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5817 if(!child_font->font)
5818 if(!load_child_font(font, child_font))
5819 continue;
5821 if(!child_font->font->ft_face)
5822 continue;
5823 g = get_glyph_index(child_font->font, c);
5824 if(g)
5826 *glyph = g;
5827 *linked_font = child_font->font;
5828 return TRUE;
5831 return FALSE;
5834 /*************************************************************
5835 * WineEngGetCharWidth
5838 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5839 LPINT buffer)
5841 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5842 UINT c;
5843 GLYPHMETRICS gm;
5844 FT_UInt glyph_index;
5845 GdiFont *linked_font;
5847 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5849 GDI_CheckNotLock();
5850 EnterCriticalSection( &freetype_cs );
5851 for(c = firstChar; c <= lastChar; c++) {
5852 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5853 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5854 &gm, 0, NULL, &identity);
5855 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5857 LeaveCriticalSection( &freetype_cs );
5858 return TRUE;
5861 /*************************************************************
5862 * WineEngGetCharABCWidths
5865 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5866 LPABC buffer)
5868 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5869 UINT c;
5870 GLYPHMETRICS gm;
5871 FT_UInt glyph_index;
5872 GdiFont *linked_font;
5874 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5876 if(!FT_IS_SCALABLE(font->ft_face))
5877 return FALSE;
5879 GDI_CheckNotLock();
5880 EnterCriticalSection( &freetype_cs );
5882 for(c = firstChar; c <= lastChar; c++) {
5883 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5884 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5885 &gm, 0, NULL, &identity);
5886 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5887 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5888 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5889 FONT_GM(linked_font,glyph_index)->bbx;
5891 LeaveCriticalSection( &freetype_cs );
5892 return TRUE;
5895 /*************************************************************
5896 * WineEngGetCharABCWidthsI
5899 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5900 LPABC buffer)
5902 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5903 UINT c;
5904 GLYPHMETRICS gm;
5905 FT_UInt glyph_index;
5906 GdiFont *linked_font;
5908 if(!FT_HAS_HORIZONTAL(font->ft_face))
5909 return FALSE;
5911 GDI_CheckNotLock();
5912 EnterCriticalSection( &freetype_cs );
5914 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5915 if (!pgi)
5916 for(c = firstChar; c < firstChar+count; c++) {
5917 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5918 &gm, 0, NULL, &identity);
5919 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5920 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5921 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5922 - FONT_GM(linked_font,c)->bbx;
5924 else
5925 for(c = 0; c < count; c++) {
5926 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5927 &gm, 0, NULL, &identity);
5928 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5929 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5930 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5931 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5934 LeaveCriticalSection( &freetype_cs );
5935 return TRUE;
5938 /*************************************************************
5939 * WineEngGetTextExtentExPoint
5942 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5943 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5945 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5946 INT idx;
5947 INT nfit = 0, ext;
5948 GLYPHMETRICS gm;
5949 TEXTMETRICW tm;
5950 FT_UInt glyph_index;
5951 GdiFont *linked_font;
5953 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5954 max_ext, size);
5956 GDI_CheckNotLock();
5957 EnterCriticalSection( &freetype_cs );
5959 size->cx = 0;
5960 WineEngGetTextMetrics(font, &tm);
5961 size->cy = tm.tmHeight;
5963 for(idx = 0; idx < count; idx++) {
5964 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5965 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5966 &gm, 0, NULL, &identity);
5967 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5968 ext = size->cx;
5969 if (! pnfit || ext <= max_ext) {
5970 ++nfit;
5971 if (dxs)
5972 dxs[idx] = ext;
5976 if (pnfit)
5977 *pnfit = nfit;
5979 LeaveCriticalSection( &freetype_cs );
5980 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5981 return TRUE;
5984 /*************************************************************
5985 * WineEngGetTextExtentExPointI
5988 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5989 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5991 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5992 INT idx;
5993 INT nfit = 0, ext;
5994 GLYPHMETRICS gm;
5995 TEXTMETRICW tm;
5997 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5999 GDI_CheckNotLock();
6000 EnterCriticalSection( &freetype_cs );
6002 size->cx = 0;
6003 WineEngGetTextMetrics(font, &tm);
6004 size->cy = tm.tmHeight;
6006 for(idx = 0; idx < count; idx++) {
6007 WineEngGetGlyphOutline(font, indices[idx],
6008 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6009 &identity);
6010 size->cx += FONT_GM(font,indices[idx])->adv;
6011 ext = size->cx;
6012 if (! pnfit || ext <= max_ext) {
6013 ++nfit;
6014 if (dxs)
6015 dxs[idx] = ext;
6019 if (pnfit)
6020 *pnfit = nfit;
6022 LeaveCriticalSection( &freetype_cs );
6023 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6024 return TRUE;
6027 /*************************************************************
6028 * WineEngGetFontData
6031 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6032 DWORD cbData)
6034 FT_Face ft_face = font->ft_face;
6035 FT_ULong len;
6036 FT_Error err;
6038 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6039 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6040 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6042 if(!FT_IS_SFNT(ft_face))
6043 return GDI_ERROR;
6045 if(!buf || !cbData)
6046 len = 0;
6047 else
6048 len = cbData;
6050 if(table) { /* MS tags differ in endianness from FT ones */
6051 table = table >> 24 | table << 24 |
6052 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6055 /* make sure value of len is the value freetype says it needs */
6056 if(buf && len)
6058 FT_ULong needed = 0;
6059 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6060 if( !err && needed < len) len = needed;
6062 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6064 if(err) {
6065 TRACE("Can't find table %c%c%c%c\n",
6066 /* bytes were reversed */
6067 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6068 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6069 return GDI_ERROR;
6071 return len;
6074 /*************************************************************
6075 * WineEngGetTextFace
6078 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6080 INT n = strlenW(font->name) + 1;
6081 if(str) {
6082 lstrcpynW(str, font->name, count);
6083 return min(count, n);
6084 } else
6085 return n;
6088 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6090 if (fs) *fs = font->fs;
6091 return font->charset;
6094 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6096 GdiFont *font = dc->gdiFont, *linked_font;
6097 struct list *first_hfont;
6098 BOOL ret;
6100 GDI_CheckNotLock();
6101 EnterCriticalSection( &freetype_cs );
6102 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6103 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6104 if(font == linked_font)
6105 *new_hfont = dc->hFont;
6106 else
6108 first_hfont = list_head(&linked_font->hfontlist);
6109 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6111 LeaveCriticalSection( &freetype_cs );
6112 return ret;
6115 /* Retrieve a list of supported Unicode ranges for a given font.
6116 * Can be called with NULL gs to calculate the buffer size. Returns
6117 * the number of ranges found.
6119 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6121 DWORD num_ranges = 0;
6123 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6125 FT_UInt glyph_code;
6126 FT_ULong char_code, char_code_prev;
6128 glyph_code = 0;
6129 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6131 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6132 face->num_glyphs, glyph_code, char_code);
6134 if (!glyph_code) return 0;
6136 if (gs)
6138 gs->ranges[0].wcLow = (USHORT)char_code;
6139 gs->ranges[0].cGlyphs = 0;
6140 gs->cGlyphsSupported = 0;
6143 num_ranges = 1;
6144 while (glyph_code)
6146 if (char_code < char_code_prev)
6148 ERR("expected increasing char code from FT_Get_Next_Char\n");
6149 return 0;
6151 if (char_code - char_code_prev > 1)
6153 num_ranges++;
6154 if (gs)
6156 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6157 gs->ranges[num_ranges - 1].cGlyphs = 1;
6158 gs->cGlyphsSupported++;
6161 else if (gs)
6163 gs->ranges[num_ranges - 1].cGlyphs++;
6164 gs->cGlyphsSupported++;
6166 char_code_prev = char_code;
6167 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6170 else
6171 FIXME("encoding %u not supported\n", face->charmap->encoding);
6173 return num_ranges;
6176 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6178 DWORD size = 0;
6179 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6181 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6182 if (glyphset)
6184 glyphset->cbThis = size;
6185 glyphset->cRanges = num_ranges;
6187 return size;
6190 /*************************************************************
6191 * FontIsLinked
6193 BOOL WineEngFontIsLinked(GdiFont *font)
6195 BOOL ret;
6196 GDI_CheckNotLock();
6197 EnterCriticalSection( &freetype_cs );
6198 ret = !list_empty(&font->child_fonts);
6199 LeaveCriticalSection( &freetype_cs );
6200 return ret;
6203 static BOOL is_hinting_enabled(void)
6205 /* Use the >= 2.2.0 function if available */
6206 if(pFT_Get_TrueType_Engine_Type)
6208 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6209 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6211 #ifdef FT_DRIVER_HAS_HINTER
6212 else
6214 FT_Module mod;
6216 /* otherwise if we've been compiled with < 2.2.0 headers
6217 use the internal macro */
6218 mod = pFT_Get_Module(library, "truetype");
6219 if(mod && FT_DRIVER_HAS_HINTER(mod))
6220 return TRUE;
6222 #endif
6224 return FALSE;
6227 static BOOL is_subpixel_rendering_enabled( void )
6229 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6230 return pFT_Library_SetLcdFilter &&
6231 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6232 #else
6233 return FALSE;
6234 #endif
6237 /*************************************************************************
6238 * GetRasterizerCaps (GDI32.@)
6240 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6242 static int hinting = -1;
6243 static int subpixel = -1;
6245 if(hinting == -1)
6247 hinting = is_hinting_enabled();
6248 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6251 if ( subpixel == -1 )
6253 subpixel = is_subpixel_rendering_enabled();
6254 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6257 lprs->nSize = sizeof(RASTERIZER_STATUS);
6258 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6259 if ( subpixel )
6260 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6261 lprs->nLanguageID = 0;
6262 return TRUE;
6265 /*************************************************************
6266 * WineEngRealizationInfo
6268 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6270 FIXME("(%p, %p): stub!\n", font, info);
6272 info->flags = 1;
6273 if(FT_IS_SCALABLE(font->ft_face))
6274 info->flags |= 2;
6276 info->cache_num = font->cache_num;
6277 info->unknown2 = -1;
6278 return TRUE;
6281 /*************************************************************************
6282 * Kerning support for TrueType fonts
6284 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6286 struct TT_kern_table
6288 USHORT version;
6289 USHORT nTables;
6292 struct TT_kern_subtable
6294 USHORT version;
6295 USHORT length;
6296 union
6298 USHORT word;
6299 struct
6301 USHORT horizontal : 1;
6302 USHORT minimum : 1;
6303 USHORT cross_stream: 1;
6304 USHORT override : 1;
6305 USHORT reserved1 : 4;
6306 USHORT format : 8;
6307 } bits;
6308 } coverage;
6311 struct TT_format0_kern_subtable
6313 USHORT nPairs;
6314 USHORT searchRange;
6315 USHORT entrySelector;
6316 USHORT rangeShift;
6319 struct TT_kern_pair
6321 USHORT left;
6322 USHORT right;
6323 short value;
6326 static DWORD parse_format0_kern_subtable(GdiFont *font,
6327 const struct TT_format0_kern_subtable *tt_f0_ks,
6328 const USHORT *glyph_to_char,
6329 KERNINGPAIR *kern_pair, DWORD cPairs)
6331 USHORT i, nPairs;
6332 const struct TT_kern_pair *tt_kern_pair;
6334 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6336 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6338 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6339 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6340 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6342 if (!kern_pair || !cPairs)
6343 return nPairs;
6345 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6347 nPairs = min(nPairs, cPairs);
6349 for (i = 0; i < nPairs; i++)
6351 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6352 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6353 /* this algorithm appears to better match what Windows does */
6354 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6355 if (kern_pair->iKernAmount < 0)
6357 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6358 kern_pair->iKernAmount -= font->ppem;
6360 else if (kern_pair->iKernAmount > 0)
6362 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6363 kern_pair->iKernAmount += font->ppem;
6365 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6367 TRACE("left %u right %u value %d\n",
6368 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6370 kern_pair++;
6372 TRACE("copied %u entries\n", nPairs);
6373 return nPairs;
6376 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6378 DWORD length;
6379 void *buf;
6380 const struct TT_kern_table *tt_kern_table;
6381 const struct TT_kern_subtable *tt_kern_subtable;
6382 USHORT i, nTables;
6383 USHORT *glyph_to_char;
6385 GDI_CheckNotLock();
6386 EnterCriticalSection( &freetype_cs );
6387 if (font->total_kern_pairs != (DWORD)-1)
6389 if (cPairs && kern_pair)
6391 cPairs = min(cPairs, font->total_kern_pairs);
6392 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6393 LeaveCriticalSection( &freetype_cs );
6394 return cPairs;
6396 LeaveCriticalSection( &freetype_cs );
6397 return font->total_kern_pairs;
6400 font->total_kern_pairs = 0;
6402 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6404 if (length == GDI_ERROR)
6406 TRACE("no kerning data in the font\n");
6407 LeaveCriticalSection( &freetype_cs );
6408 return 0;
6411 buf = HeapAlloc(GetProcessHeap(), 0, length);
6412 if (!buf)
6414 WARN("Out of memory\n");
6415 LeaveCriticalSection( &freetype_cs );
6416 return 0;
6419 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6421 /* build a glyph index to char code map */
6422 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6423 if (!glyph_to_char)
6425 WARN("Out of memory allocating a glyph index to char code map\n");
6426 HeapFree(GetProcessHeap(), 0, buf);
6427 LeaveCriticalSection( &freetype_cs );
6428 return 0;
6431 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6433 FT_UInt glyph_code;
6434 FT_ULong char_code;
6436 glyph_code = 0;
6437 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6439 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6440 font->ft_face->num_glyphs, glyph_code, char_code);
6442 while (glyph_code)
6444 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6446 /* FIXME: This doesn't match what Windows does: it does some fancy
6447 * things with duplicate glyph index to char code mappings, while
6448 * we just avoid overriding existing entries.
6450 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6451 glyph_to_char[glyph_code] = (USHORT)char_code;
6453 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6456 else
6458 ULONG n;
6460 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6461 for (n = 0; n <= 65535; n++)
6462 glyph_to_char[n] = (USHORT)n;
6465 tt_kern_table = buf;
6466 nTables = GET_BE_WORD(tt_kern_table->nTables);
6467 TRACE("version %u, nTables %u\n",
6468 GET_BE_WORD(tt_kern_table->version), nTables);
6470 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6472 for (i = 0; i < nTables; i++)
6474 struct TT_kern_subtable tt_kern_subtable_copy;
6476 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6477 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6478 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6480 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6481 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6482 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6484 /* According to the TrueType specification this is the only format
6485 * that will be properly interpreted by Windows and OS/2
6487 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6489 DWORD new_chunk, old_total = font->total_kern_pairs;
6491 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6492 glyph_to_char, NULL, 0);
6493 font->total_kern_pairs += new_chunk;
6495 if (!font->kern_pairs)
6496 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6497 font->total_kern_pairs * sizeof(*font->kern_pairs));
6498 else
6499 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6500 font->total_kern_pairs * sizeof(*font->kern_pairs));
6502 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6503 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6505 else
6506 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6508 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6511 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6512 HeapFree(GetProcessHeap(), 0, buf);
6514 if (cPairs && kern_pair)
6516 cPairs = min(cPairs, font->total_kern_pairs);
6517 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6518 LeaveCriticalSection( &freetype_cs );
6519 return cPairs;
6521 LeaveCriticalSection( &freetype_cs );
6522 return font->total_kern_pairs;
6525 #else /* HAVE_FREETYPE */
6527 /*************************************************************************/
6529 BOOL WineEngInit(void)
6531 return FALSE;
6533 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6535 return NULL;
6537 BOOL WineEngDestroyFontInstance(HFONT hfont)
6539 return FALSE;
6542 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6544 return 1;
6547 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6548 LPWORD pgi, DWORD flags)
6550 return GDI_ERROR;
6553 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6554 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6555 const MAT2* lpmat)
6557 ERR("called but we don't have FreeType\n");
6558 return GDI_ERROR;
6561 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6563 ERR("called but we don't have FreeType\n");
6564 return FALSE;
6567 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6568 OUTLINETEXTMETRICW *potm)
6570 ERR("called but we don't have FreeType\n");
6571 return 0;
6574 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6575 LPINT buffer)
6577 ERR("called but we don't have FreeType\n");
6578 return FALSE;
6581 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6582 LPABC buffer)
6584 ERR("called but we don't have FreeType\n");
6585 return FALSE;
6588 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6589 LPABC buffer)
6591 ERR("called but we don't have FreeType\n");
6592 return FALSE;
6595 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6596 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6598 ERR("called but we don't have FreeType\n");
6599 return FALSE;
6602 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6603 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6605 ERR("called but we don't have FreeType\n");
6606 return FALSE;
6609 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6610 DWORD cbData)
6612 ERR("called but we don't have FreeType\n");
6613 return GDI_ERROR;
6616 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6618 ERR("called but we don't have FreeType\n");
6619 return 0;
6622 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6624 FIXME(":stub\n");
6625 return 1;
6628 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6630 FIXME(":stub\n");
6631 return TRUE;
6634 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6636 FIXME(":stub\n");
6637 return NULL;
6640 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6642 FIXME(":stub\n");
6643 return DEFAULT_CHARSET;
6646 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6648 return FALSE;
6651 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6653 FIXME("(%p, %p): stub\n", font, glyphset);
6654 return 0;
6657 BOOL WineEngFontIsLinked(GdiFont *font)
6659 return FALSE;
6662 /*************************************************************************
6663 * GetRasterizerCaps (GDI32.@)
6665 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6667 lprs->nSize = sizeof(RASTERIZER_STATUS);
6668 lprs->wFlags = 0;
6669 lprs->nLanguageID = 0;
6670 return TRUE;
6673 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6675 ERR("called but we don't have FreeType\n");
6676 return 0;
6679 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6681 ERR("called but we don't have FreeType\n");
6682 return FALSE;
6685 #endif /* HAVE_FREETYPE */