push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / gdi32 / freetype.c
blobef934025fa3017183822d6e60ea9db6d73b1ab30
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 #else
113 # ifdef HAVE_FREETYPE_FTNAMES_H
114 # include <freetype/ftnames.h>
115 # endif
116 #endif
117 #ifdef HAVE_FREETYPE_TTNAMEID_H
118 #include <freetype/ttnameid.h>
119 #endif
120 #ifdef HAVE_FREETYPE_FTOUTLN_H
121 #include <freetype/ftoutln.h>
122 #endif
123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
124 #include <freetype/internal/sfnt.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTTRIGON_H
127 #include <freetype/fttrigon.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTWINFNT_H
130 #include <freetype/ftwinfnt.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTMODAPI_H
133 #include <freetype/ftmodapi.h>
134 #endif
135 #ifdef HAVE_FREETYPE_FTLCDFIL_H
136 #include <freetype/ftlcdfil.h>
137 #endif
139 #ifndef HAVE_FT_TRUETYPEENGINETYPE
140 typedef enum
142 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
143 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
144 FT_TRUETYPE_ENGINE_TYPE_PATENTED
145 } FT_TrueTypeEngineType;
146 #endif
148 static FT_Library library = 0;
149 typedef struct
151 FT_Int major;
152 FT_Int minor;
153 FT_Int patch;
154 } FT_Version_t;
155 static FT_Version_t FT_Version;
156 static DWORD FT_SimpleVersion;
158 static void *ft_handle = NULL;
160 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
161 MAKE_FUNCPTR(FT_Vector_Unit);
162 MAKE_FUNCPTR(FT_Done_Face);
163 MAKE_FUNCPTR(FT_Get_Char_Index);
164 MAKE_FUNCPTR(FT_Get_Module);
165 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
166 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
167 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
168 MAKE_FUNCPTR(FT_Init_FreeType);
169 MAKE_FUNCPTR(FT_Load_Glyph);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Select_Charmap);
182 MAKE_FUNCPTR(FT_Set_Charmap);
183 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
184 MAKE_FUNCPTR(FT_Vector_Transform);
185 MAKE_FUNCPTR(FT_Render_Glyph);
186 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
187 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
188 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
189 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
190 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
191 #ifdef HAVE_FREETYPE_FTLCDFIL_H
192 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
193 #endif
194 #ifdef HAVE_FREETYPE_FTWINFNT_H
195 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
196 #endif
198 #ifdef SONAME_LIBFONTCONFIG
199 #include <fontconfig/fontconfig.h>
200 MAKE_FUNCPTR(FcConfigGetCurrent);
201 MAKE_FUNCPTR(FcFontList);
202 MAKE_FUNCPTR(FcFontSetDestroy);
203 MAKE_FUNCPTR(FcInit);
204 MAKE_FUNCPTR(FcObjectSetAdd);
205 MAKE_FUNCPTR(FcObjectSetCreate);
206 MAKE_FUNCPTR(FcObjectSetDestroy);
207 MAKE_FUNCPTR(FcPatternCreate);
208 MAKE_FUNCPTR(FcPatternDestroy);
209 MAKE_FUNCPTR(FcPatternGetBool);
210 MAKE_FUNCPTR(FcPatternGetString);
211 #endif
213 #undef MAKE_FUNCPTR
215 #ifndef FT_MAKE_TAG
216 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
217 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
218 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
219 #endif
221 #ifndef ft_encoding_none
222 #define FT_ENCODING_NONE ft_encoding_none
223 #endif
224 #ifndef ft_encoding_ms_symbol
225 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
226 #endif
227 #ifndef ft_encoding_unicode
228 #define FT_ENCODING_UNICODE ft_encoding_unicode
229 #endif
230 #ifndef ft_encoding_apple_roman
231 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
232 #endif
234 #ifdef WORDS_BIGENDIAN
235 #define GET_BE_WORD(x) (x)
236 #else
237 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
238 #endif
240 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 typedef struct {
242 FT_Short height;
243 FT_Short width;
244 FT_Pos size;
245 FT_Pos x_ppem;
246 FT_Pos y_ppem;
247 FT_Short internal_leading;
248 } Bitmap_Size;
250 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
251 So to let this compile on older versions of FreeType we'll define the
252 new structure here. */
253 typedef struct {
254 FT_Short height, width;
255 FT_Pos size, x_ppem, y_ppem;
256 } My_FT_Bitmap_Size;
258 struct enum_data
260 ENUMLOGFONTEXW elf;
261 NEWTEXTMETRICEXW ntm;
262 DWORD type;
265 typedef struct tagFace {
266 struct list entry;
267 WCHAR *StyleName;
268 char *file;
269 void *font_data_ptr;
270 DWORD font_data_size;
271 FT_Long face_index;
272 FONTSIGNATURE fs;
273 FONTSIGNATURE fs_links;
274 DWORD ntmFlags;
275 FT_Fixed font_version;
276 BOOL scalable;
277 Bitmap_Size size; /* set if face is a bitmap */
278 BOOL external; /* TRUE if we should manually add this font to the registry */
279 struct tagFamily *family;
280 /* Cached data for Enum */
281 struct enum_data *cached_enum_data;
282 } Face;
284 typedef struct tagFamily {
285 struct list entry;
286 const WCHAR *FamilyName;
287 struct list faces;
288 } Family;
290 typedef struct {
291 GLYPHMETRICS gm;
292 INT adv; /* These three hold to widths of the unrotated chars */
293 INT lsb;
294 INT bbx;
295 BOOL init;
296 } GM;
298 typedef struct {
299 FLOAT eM11, eM12;
300 FLOAT eM21, eM22;
301 } FMAT2;
303 typedef struct {
304 DWORD hash;
305 LOGFONTW lf;
306 FMAT2 matrix;
307 BOOL can_use_bitmap;
308 } FONT_DESC;
310 typedef struct tagHFONTLIST {
311 struct list entry;
312 HFONT hfont;
313 } HFONTLIST;
315 typedef struct {
316 struct list entry;
317 Face *face;
318 GdiFont *font;
319 } CHILD_FONT;
321 struct tagGdiFont {
322 struct list entry;
323 GM **gm;
324 DWORD gmsize;
325 struct list hfontlist;
326 OUTLINETEXTMETRICW *potm;
327 DWORD total_kern_pairs;
328 KERNINGPAIR *kern_pairs;
329 struct list child_fonts;
331 /* the following members can be accessed without locking, they are never modified after creation */
332 FT_Face ft_face;
333 struct font_mapping *mapping;
334 LPWSTR name;
335 int charset;
336 int codepage;
337 BOOL fake_italic;
338 BOOL fake_bold;
339 BYTE underline;
340 BYTE strikeout;
341 INT orientation;
342 FONT_DESC font_desc;
343 LONG aveWidth, ppem;
344 double scale_y;
345 SHORT yMax;
346 SHORT yMin;
347 DWORD ntmFlags;
348 FONTSIGNATURE fs;
349 GdiFont *base_font;
350 VOID *GSUB_Table;
351 DWORD cache_num;
354 typedef struct {
355 struct list entry;
356 const WCHAR *font_name;
357 struct list links;
358 } SYSTEM_LINKS;
360 #define GM_BLOCK_SIZE 128
361 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
363 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
364 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
365 #define UNUSED_CACHE_SIZE 10
366 static struct list child_font_list = LIST_INIT(child_font_list);
367 static struct list system_links = LIST_INIT(system_links);
369 static struct list font_subst_list = LIST_INIT(font_subst_list);
371 static struct list font_list = LIST_INIT(font_list);
373 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
374 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
375 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
377 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
378 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
379 'W','i','n','d','o','w','s','\\',
380 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
381 'F','o','n','t','s','\0'};
383 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
384 'W','i','n','d','o','w','s',' ','N','T','\\',
385 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
386 'F','o','n','t','s','\0'};
388 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
389 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
390 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
391 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
393 static const WCHAR * const SystemFontValues[4] = {
394 System_Value,
395 OEMFont_Value,
396 FixedSys_Value,
397 NULL
400 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
401 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
403 /* Interesting and well-known (frequently-assumed!) font names */
404 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
405 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 };
406 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
407 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
408 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
409 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
410 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
411 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
413 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
414 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
415 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
416 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
417 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
418 'E','u','r','o','p','e','a','n','\0'};
419 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
420 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
421 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
422 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
423 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
424 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
425 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
426 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
427 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
428 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
429 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
430 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
432 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
433 WesternW, /*00*/
434 Central_EuropeanW,
435 CyrillicW,
436 GreekW,
437 TurkishW,
438 HebrewW,
439 ArabicW,
440 BalticW,
441 VietnameseW, /*08*/
442 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
443 ThaiW,
444 JapaneseW,
445 CHINESE_GB2312W,
446 HangulW,
447 CHINESE_BIG5W,
448 Hangul_Johab_W,
449 NULL, NULL, /*23*/
450 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
451 SymbolW /*31*/
454 typedef struct {
455 WCHAR *name;
456 INT charset;
457 } NameCs;
459 typedef struct tagFontSubst {
460 struct list entry;
461 NameCs from;
462 NameCs to;
463 } FontSubst;
465 struct font_mapping
467 struct list entry;
468 int refcount;
469 dev_t dev;
470 ino_t ino;
471 void *data;
472 size_t size;
475 static struct list mappings_list = LIST_INIT( mappings_list );
477 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
479 static CRITICAL_SECTION freetype_cs;
480 static CRITICAL_SECTION_DEBUG critsect_debug =
482 0, 0, &freetype_cs,
483 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
484 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
486 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
488 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
490 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
491 static BOOL use_default_fallback = FALSE;
493 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
495 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
496 'W','i','n','d','o','w','s',' ','N','T','\\',
497 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
498 'S','y','s','t','e','m','L','i','n','k',0};
500 /****************************************
501 * Notes on .fon files
503 * The fonts System, FixedSys and Terminal are special. There are typically multiple
504 * versions installed for different resolutions and codepages. Windows stores which one to use
505 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
506 * Key Meaning
507 * FIXEDFON.FON FixedSys
508 * FONTS.FON System
509 * OEMFONT.FON Terminal
510 * LogPixels Current dpi set by the display control panel applet
511 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
512 * also has a LogPixels value that appears to mirror this)
514 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
515 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
516 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
517 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
518 * so that makes sense.
520 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
521 * to be mapped into the registry on Windows 2000 at least).
522 * I have
523 * woafont=app850.fon
524 * ega80woa.fon=ega80850.fon
525 * ega40woa.fon=ega40850.fon
526 * cga80woa.fon=cga80850.fon
527 * cga40woa.fon=cga40850.fon
530 /* These are all structures needed for the GSUB table */
532 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
533 #define TATEGAKI_LOWER_BOUND 0x02F1
535 typedef struct {
536 DWORD version;
537 WORD ScriptList;
538 WORD FeatureList;
539 WORD LookupList;
540 } GSUB_Header;
542 typedef struct {
543 CHAR ScriptTag[4];
544 WORD Script;
545 } GSUB_ScriptRecord;
547 typedef struct {
548 WORD ScriptCount;
549 GSUB_ScriptRecord ScriptRecord[1];
550 } GSUB_ScriptList;
552 typedef struct {
553 CHAR LangSysTag[4];
554 WORD LangSys;
555 } GSUB_LangSysRecord;
557 typedef struct {
558 WORD DefaultLangSys;
559 WORD LangSysCount;
560 GSUB_LangSysRecord LangSysRecord[1];
561 } GSUB_Script;
563 typedef struct {
564 WORD LookupOrder; /* Reserved */
565 WORD ReqFeatureIndex;
566 WORD FeatureCount;
567 WORD FeatureIndex[1];
568 } GSUB_LangSys;
570 typedef struct {
571 CHAR FeatureTag[4];
572 WORD Feature;
573 } GSUB_FeatureRecord;
575 typedef struct {
576 WORD FeatureCount;
577 GSUB_FeatureRecord FeatureRecord[1];
578 } GSUB_FeatureList;
580 typedef struct {
581 WORD FeatureParams; /* Reserved */
582 WORD LookupCount;
583 WORD LookupListIndex[1];
584 } GSUB_Feature;
586 typedef struct {
587 WORD LookupCount;
588 WORD Lookup[1];
589 } GSUB_LookupList;
591 typedef struct {
592 WORD LookupType;
593 WORD LookupFlag;
594 WORD SubTableCount;
595 WORD SubTable[1];
596 } GSUB_LookupTable;
598 typedef struct {
599 WORD CoverageFormat;
600 WORD GlyphCount;
601 WORD GlyphArray[1];
602 } GSUB_CoverageFormat1;
604 typedef struct {
605 WORD Start;
606 WORD End;
607 WORD StartCoverageIndex;
608 } GSUB_RangeRecord;
610 typedef struct {
611 WORD CoverageFormat;
612 WORD RangeCount;
613 GSUB_RangeRecord RangeRecord[1];
614 } GSUB_CoverageFormat2;
616 typedef struct {
617 WORD SubstFormat; /* = 1 */
618 WORD Coverage;
619 WORD DeltaGlyphID;
620 } GSUB_SingleSubstFormat1;
622 typedef struct {
623 WORD SubstFormat; /* = 2 */
624 WORD Coverage;
625 WORD GlyphCount;
626 WORD Substitute[1];
627 }GSUB_SingleSubstFormat2;
629 #ifdef HAVE_CARBON_CARBON_H
630 static char *find_cache_dir(void)
632 FSRef ref;
633 OSErr err;
634 static char cached_path[MAX_PATH];
635 static const char *wine = "/Wine", *fonts = "/Fonts";
637 if(*cached_path) return cached_path;
639 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
640 if(err != noErr)
642 WARN("can't create cached data folder\n");
643 return NULL;
645 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
646 if(err != noErr)
648 WARN("can't create cached data path\n");
649 *cached_path = '\0';
650 return NULL;
652 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
654 ERR("Could not create full path\n");
655 *cached_path = '\0';
656 return NULL;
658 strcat(cached_path, wine);
660 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
662 WARN("Couldn't mkdir %s\n", cached_path);
663 *cached_path = '\0';
664 return NULL;
666 strcat(cached_path, fonts);
667 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
669 WARN("Couldn't mkdir %s\n", cached_path);
670 *cached_path = '\0';
671 return NULL;
673 return cached_path;
676 /******************************************************************
677 * expand_mac_font
679 * Extracts individual TrueType font files from a Mac suitcase font
680 * and saves them into the user's caches directory (see
681 * find_cache_dir()).
682 * Returns a NULL terminated array of filenames.
684 * We do this because they are apps that try to read ttf files
685 * themselves and they don't like Mac suitcase files.
687 static char **expand_mac_font(const char *path)
689 FSRef ref;
690 SInt16 res_ref;
691 OSStatus s;
692 unsigned int idx;
693 const char *out_dir;
694 const char *filename;
695 int output_len;
696 struct {
697 char **array;
698 unsigned int size, max_size;
699 } ret;
701 TRACE("path %s\n", path);
703 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
704 if(s != noErr)
706 WARN("failed to get ref\n");
707 return NULL;
710 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
711 if(s != noErr)
713 TRACE("no data fork, so trying resource fork\n");
714 res_ref = FSOpenResFile(&ref, fsRdPerm);
715 if(res_ref == -1)
717 TRACE("unable to open resource fork\n");
718 return NULL;
722 ret.size = 0;
723 ret.max_size = 10;
724 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
725 if(!ret.array)
727 CloseResFile(res_ref);
728 return NULL;
731 out_dir = find_cache_dir();
733 filename = strrchr(path, '/');
734 if(!filename) filename = path;
735 else filename++;
737 /* output filename has the form out_dir/filename_%04x.ttf */
738 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
740 UseResFile(res_ref);
741 idx = 1;
742 while(1)
744 FamRec *fam_rec;
745 unsigned short *num_faces_ptr, num_faces, face;
746 AsscEntry *assoc;
747 Handle fond;
748 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
750 fond = Get1IndResource(fond_res, idx);
751 if(!fond) break;
752 TRACE("got fond resource %d\n", idx);
753 HLock(fond);
755 fam_rec = *(FamRec**)fond;
756 num_faces_ptr = (unsigned short *)(fam_rec + 1);
757 num_faces = GET_BE_WORD(*num_faces_ptr);
758 num_faces++;
759 assoc = (AsscEntry*)(num_faces_ptr + 1);
760 TRACE("num faces %04x\n", num_faces);
761 for(face = 0; face < num_faces; face++, assoc++)
763 Handle sfnt;
764 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
765 unsigned short size, font_id;
766 char *output;
768 size = GET_BE_WORD(assoc->fontSize);
769 font_id = GET_BE_WORD(assoc->fontID);
770 if(size != 0)
772 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
773 continue;
776 TRACE("trying to load sfnt id %04x\n", font_id);
777 sfnt = GetResource(sfnt_res, font_id);
778 if(!sfnt)
780 TRACE("can't get sfnt resource %04x\n", font_id);
781 continue;
784 output = HeapAlloc(GetProcessHeap(), 0, output_len);
785 if(output)
787 int fd;
789 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
791 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
792 if(fd != -1 || errno == EEXIST)
794 if(fd != -1)
796 unsigned char *sfnt_data;
798 HLock(sfnt);
799 sfnt_data = *(unsigned char**)sfnt;
800 write(fd, sfnt_data, GetHandleSize(sfnt));
801 HUnlock(sfnt);
802 close(fd);
804 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
806 ret.max_size *= 2;
807 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
809 ret.array[ret.size++] = output;
811 else
813 WARN("unable to create %s\n", output);
814 HeapFree(GetProcessHeap(), 0, output);
817 ReleaseResource(sfnt);
819 HUnlock(fond);
820 ReleaseResource(fond);
821 idx++;
823 CloseResFile(res_ref);
825 return ret.array;
828 #endif /* HAVE_CARBON_CARBON_H */
830 static inline BOOL is_win9x(void)
832 return GetVersion() & 0x80000000;
835 This function builds an FT_Fixed from a double. It fails if the absolute
836 value of the float number is greater than 32768.
838 static inline FT_Fixed FT_FixedFromFloat(double f)
840 return f * 0x10000;
844 This function builds an FT_Fixed from a FIXED. It simply put f.value
845 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
847 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
849 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
853 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
855 Family *family;
856 Face *face;
857 const char *file;
858 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
859 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
861 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
862 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
864 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
866 if(face_name && strcmpiW(face_name, family->FamilyName))
867 continue;
868 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
870 if (!face->file)
871 continue;
872 file = strrchr(face->file, '/');
873 if(!file)
874 file = face->file;
875 else
876 file++;
877 if(!strcasecmp(file, file_nameA))
879 HeapFree(GetProcessHeap(), 0, file_nameA);
880 return face;
884 HeapFree(GetProcessHeap(), 0, file_nameA);
885 return NULL;
888 static Family *find_family_from_name(const WCHAR *name)
890 Family *family;
892 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
894 if(!strcmpiW(family->FamilyName, name))
895 return family;
898 return NULL;
901 static void DumpSubstList(void)
903 FontSubst *psub;
905 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
907 if(psub->from.charset != -1 || psub->to.charset != -1)
908 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
909 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
910 else
911 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
912 debugstr_w(psub->to.name));
914 return;
917 static LPWSTR strdupW(LPCWSTR p)
919 LPWSTR ret;
920 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
921 ret = HeapAlloc(GetProcessHeap(), 0, len);
922 memcpy(ret, p, len);
923 return ret;
926 static LPSTR strdupA(LPCSTR p)
928 LPSTR ret;
929 DWORD len = (strlen(p) + 1);
930 ret = HeapAlloc(GetProcessHeap(), 0, len);
931 memcpy(ret, p, len);
932 return ret;
935 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
936 INT from_charset)
938 FontSubst *element;
940 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
942 if(!strcmpiW(element->from.name, from_name) &&
943 (element->from.charset == from_charset ||
944 element->from.charset == -1))
945 return element;
948 return NULL;
951 #define ADD_FONT_SUBST_FORCE 1
953 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
955 FontSubst *from_exist, *to_exist;
957 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
959 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
961 list_remove(&from_exist->entry);
962 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
963 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
964 HeapFree(GetProcessHeap(), 0, from_exist);
965 from_exist = NULL;
968 if(!from_exist)
970 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
972 if(to_exist)
974 HeapFree(GetProcessHeap(), 0, subst->to.name);
975 subst->to.name = strdupW(to_exist->to.name);
978 list_add_tail(subst_list, &subst->entry);
980 return TRUE;
983 HeapFree(GetProcessHeap(), 0, subst->from.name);
984 HeapFree(GetProcessHeap(), 0, subst->to.name);
985 HeapFree(GetProcessHeap(), 0, subst);
986 return FALSE;
989 static void split_subst_info(NameCs *nc, LPSTR str)
991 CHAR *p = strrchr(str, ',');
992 DWORD len;
994 nc->charset = -1;
995 if(p && *(p+1)) {
996 nc->charset = strtol(p+1, NULL, 10);
997 *p = '\0';
999 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1000 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1001 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1004 static void LoadSubstList(void)
1006 FontSubst *psub;
1007 HKEY hkey;
1008 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1009 LPSTR value;
1010 LPVOID data;
1012 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1013 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1014 &hkey) == ERROR_SUCCESS) {
1016 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1017 &valuelen, &datalen, NULL, NULL);
1019 valuelen++; /* returned value doesn't include room for '\0' */
1020 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1021 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1023 dlen = datalen;
1024 vlen = valuelen;
1025 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1026 &dlen) == ERROR_SUCCESS) {
1027 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1029 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1030 split_subst_info(&psub->from, value);
1031 split_subst_info(&psub->to, data);
1033 /* Win 2000 doesn't allow mapping between different charsets
1034 or mapping of DEFAULT_CHARSET */
1035 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1036 psub->to.charset == DEFAULT_CHARSET) {
1037 HeapFree(GetProcessHeap(), 0, psub->to.name);
1038 HeapFree(GetProcessHeap(), 0, psub->from.name);
1039 HeapFree(GetProcessHeap(), 0, psub);
1040 } else {
1041 add_font_subst(&font_subst_list, psub, 0);
1043 /* reset dlen and vlen */
1044 dlen = datalen;
1045 vlen = valuelen;
1047 HeapFree(GetProcessHeap(), 0, data);
1048 HeapFree(GetProcessHeap(), 0, value);
1049 RegCloseKey(hkey);
1054 /*****************************************************************
1055 * get_name_table_entry
1057 * Supply the platform, encoding, language and name ids in req
1058 * and if the name exists the function will fill in the string
1059 * and string_len members. The string is owned by FreeType so
1060 * don't free it. Returns TRUE if the name is found else FALSE.
1062 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1064 FT_SfntName name;
1065 FT_UInt num_names, name_index;
1067 if(FT_IS_SFNT(ft_face))
1069 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1071 for(name_index = 0; name_index < num_names; name_index++)
1073 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1075 if((name.platform_id == req->platform_id) &&
1076 (name.encoding_id == req->encoding_id) &&
1077 (name.language_id == req->language_id) &&
1078 (name.name_id == req->name_id))
1080 req->string = name.string;
1081 req->string_len = name.string_len;
1082 return TRUE;
1087 req->string = NULL;
1088 req->string_len = 0;
1089 return FALSE;
1092 static WCHAR *get_familyname(FT_Face ft_face)
1094 WCHAR *family = NULL;
1095 FT_SfntName name;
1097 name.platform_id = TT_PLATFORM_MICROSOFT;
1098 name.encoding_id = TT_MS_ID_UNICODE_CS;
1099 name.language_id = GetUserDefaultLCID();
1100 name.name_id = TT_NAME_ID_FONT_FAMILY;
1102 if(get_name_table_entry(ft_face, &name))
1104 FT_UInt i;
1106 /* String is not nul terminated and string_len is a byte length. */
1107 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1108 for(i = 0; i < name.string_len / 2; i++)
1110 WORD *tmp = (WORD *)&name.string[i * 2];
1111 family[i] = GET_BE_WORD(*tmp);
1113 family[i] = 0;
1114 TRACE("Got localised name %s\n", debugstr_w(family));
1117 return family;
1121 /*****************************************************************
1122 * load_sfnt_table
1124 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1125 * of FreeType that don't export this function.
1128 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1131 FT_Error err;
1133 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1134 if(pFT_Load_Sfnt_Table)
1136 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1138 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1139 else /* Do it the hard way */
1141 TT_Face tt_face = (TT_Face) ft_face;
1142 SFNT_Interface *sfnt;
1143 if (FT_Version.major==2 && FT_Version.minor==0)
1145 /* 2.0.x */
1146 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1148 else
1150 /* A field was added in the middle of the structure in 2.1.x */
1151 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1153 err = sfnt->load_any(tt_face, table, offset, buf, len);
1155 #else
1156 else
1158 static int msg;
1159 if(!msg)
1161 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1162 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1163 "Please upgrade your freetype library.\n");
1164 msg++;
1166 err = FT_Err_Unimplemented_Feature;
1168 #endif
1169 return err;
1172 static inline int TestStyles(DWORD flags, DWORD styles)
1174 return (flags & styles) == styles;
1177 static int StyleOrdering(Face *face)
1179 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1180 return 3;
1181 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1182 return 2;
1183 if (TestStyles(face->ntmFlags, NTM_BOLD))
1184 return 1;
1185 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1186 return 0;
1188 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1189 debugstr_w(face->family->FamilyName),
1190 debugstr_w(face->StyleName),
1191 face->ntmFlags);
1193 return 9999;
1196 /* Add a style of face to a font family using an ordering of the list such
1197 that regular fonts come before bold and italic, and single styles come
1198 before compound styles. */
1199 static void AddFaceToFamily(Face *face, Family *family)
1201 struct list *entry;
1203 LIST_FOR_EACH( entry, &family->faces )
1205 Face *ent = LIST_ENTRY(entry, Face, entry);
1206 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1208 list_add_before( entry, &face->entry );
1211 #define ADDFONT_EXTERNAL_FONT 0x01
1212 #define ADDFONT_FORCE_BITMAP 0x02
1213 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1215 FT_Face ft_face;
1216 TT_OS2 *pOS2;
1217 TT_Header *pHeader = NULL;
1218 WCHAR *english_family, *localised_family, *StyleW;
1219 DWORD len;
1220 Family *family;
1221 Face *face;
1222 struct list *family_elem_ptr, *face_elem_ptr;
1223 FT_Error err;
1224 FT_Long face_index = 0, num_faces;
1225 #ifdef HAVE_FREETYPE_FTWINFNT_H
1226 FT_WinFNT_HeaderRec winfnt_header;
1227 #endif
1228 int i, bitmap_num, internal_leading;
1229 FONTSIGNATURE fs;
1231 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1232 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1234 #ifdef HAVE_CARBON_CARBON_H
1235 if(file && !fake_family)
1237 char **mac_list = expand_mac_font(file);
1238 if(mac_list)
1240 BOOL had_one = FALSE;
1241 char **cursor;
1242 for(cursor = mac_list; *cursor; cursor++)
1244 had_one = TRUE;
1245 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1246 HeapFree(GetProcessHeap(), 0, *cursor);
1248 HeapFree(GetProcessHeap(), 0, mac_list);
1249 if(had_one)
1250 return 1;
1253 #endif /* HAVE_CARBON_CARBON_H */
1255 do {
1256 char *family_name = fake_family;
1258 if (file)
1260 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1261 err = pFT_New_Face(library, file, face_index, &ft_face);
1262 } else
1264 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1265 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1268 if(err != 0) {
1269 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1270 return 0;
1273 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*/
1274 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1275 pFT_Done_Face(ft_face);
1276 return 0;
1279 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1280 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1281 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1282 pFT_Done_Face(ft_face);
1283 return 0;
1286 if(FT_IS_SFNT(ft_face))
1288 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1289 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1290 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1292 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1293 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1294 pFT_Done_Face(ft_face);
1295 return 0;
1298 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1299 we don't want to load these. */
1300 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1302 FT_ULong len = 0;
1304 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1306 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1307 pFT_Done_Face(ft_face);
1308 return 0;
1313 if(!ft_face->family_name || !ft_face->style_name) {
1314 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1315 pFT_Done_Face(ft_face);
1316 return 0;
1319 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1321 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1322 pFT_Done_Face(ft_face);
1323 return 0;
1326 if (target_family)
1328 localised_family = get_familyname(ft_face);
1329 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1331 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1332 HeapFree(GetProcessHeap(), 0, localised_family);
1333 num_faces = ft_face->num_faces;
1334 pFT_Done_Face(ft_face);
1335 continue;
1337 HeapFree(GetProcessHeap(), 0, localised_family);
1340 if(!family_name)
1341 family_name = ft_face->family_name;
1343 bitmap_num = 0;
1344 do {
1345 My_FT_Bitmap_Size *size = NULL;
1346 FT_ULong tmp_size;
1348 if(!FT_IS_SCALABLE(ft_face))
1349 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1351 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1352 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1353 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1355 localised_family = NULL;
1356 if(!fake_family) {
1357 localised_family = get_familyname(ft_face);
1358 if(localised_family && !strcmpiW(localised_family, english_family)) {
1359 HeapFree(GetProcessHeap(), 0, localised_family);
1360 localised_family = NULL;
1364 family = NULL;
1365 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1366 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1367 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1368 break;
1369 family = NULL;
1371 if(!family) {
1372 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1373 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1374 list_init(&family->faces);
1375 list_add_tail(&font_list, &family->entry);
1377 if(localised_family) {
1378 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1379 subst->from.name = strdupW(english_family);
1380 subst->from.charset = -1;
1381 subst->to.name = strdupW(localised_family);
1382 subst->to.charset = -1;
1383 add_font_subst(&font_subst_list, subst, 0);
1386 HeapFree(GetProcessHeap(), 0, localised_family);
1387 HeapFree(GetProcessHeap(), 0, english_family);
1389 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1390 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1391 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1393 internal_leading = 0;
1394 memset(&fs, 0, sizeof(fs));
1396 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1397 if(pOS2) {
1398 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1399 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1400 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1401 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1402 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1403 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1404 if(pOS2->version == 0) {
1405 FT_UInt dummy;
1407 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1408 fs.fsCsb[0] |= FS_LATIN1;
1409 else
1410 fs.fsCsb[0] |= FS_SYMBOL;
1413 #ifdef HAVE_FREETYPE_FTWINFNT_H
1414 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1415 CHARSETINFO csi;
1416 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1417 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1418 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1419 fs = csi.fs;
1420 internal_leading = winfnt_header.internal_leading;
1422 #endif
1424 face_elem_ptr = list_head(&family->faces);
1425 while(face_elem_ptr) {
1426 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1427 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1428 if(!strcmpiW(face->StyleName, StyleW) &&
1429 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1430 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1431 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1432 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1434 if(fake_family) {
1435 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1436 HeapFree(GetProcessHeap(), 0, StyleW);
1437 pFT_Done_Face(ft_face);
1438 return 1;
1440 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1441 TRACE("Original font is newer so skipping this one\n");
1442 HeapFree(GetProcessHeap(), 0, StyleW);
1443 pFT_Done_Face(ft_face);
1444 return 1;
1445 } else {
1446 TRACE("Replacing original with this one\n");
1447 list_remove(&face->entry);
1448 HeapFree(GetProcessHeap(), 0, face->file);
1449 HeapFree(GetProcessHeap(), 0, face->StyleName);
1450 HeapFree(GetProcessHeap(), 0, face);
1451 break;
1455 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1456 face->cached_enum_data = NULL;
1457 face->StyleName = StyleW;
1458 if (file)
1460 face->file = strdupA(file);
1461 face->font_data_ptr = NULL;
1462 face->font_data_size = 0;
1464 else
1466 face->file = NULL;
1467 face->font_data_ptr = font_data_ptr;
1468 face->font_data_size = font_data_size;
1470 face->face_index = face_index;
1471 face->ntmFlags = 0;
1472 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1473 face->ntmFlags |= NTM_ITALIC;
1474 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1475 face->ntmFlags |= NTM_BOLD;
1476 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1477 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1478 face->family = family;
1479 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1480 face->fs = fs;
1481 memset(&face->fs_links, 0, sizeof(face->fs_links));
1483 if(FT_IS_SCALABLE(ft_face)) {
1484 memset(&face->size, 0, sizeof(face->size));
1485 face->scalable = TRUE;
1486 } else {
1487 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1488 size->height, size->width, size->size >> 6,
1489 size->x_ppem >> 6, size->y_ppem >> 6);
1490 face->size.height = size->height;
1491 face->size.width = size->width;
1492 face->size.size = size->size;
1493 face->size.x_ppem = size->x_ppem;
1494 face->size.y_ppem = size->y_ppem;
1495 face->size.internal_leading = internal_leading;
1496 face->scalable = FALSE;
1499 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1500 tmp_size = 0;
1501 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1503 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1504 face->ntmFlags |= NTM_PS_OPENTYPE;
1507 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1508 face->fs.fsCsb[0], face->fs.fsCsb[1],
1509 face->fs.fsUsb[0], face->fs.fsUsb[1],
1510 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1513 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1514 for(i = 0; i < ft_face->num_charmaps; i++) {
1515 switch(ft_face->charmaps[i]->encoding) {
1516 case FT_ENCODING_UNICODE:
1517 case FT_ENCODING_APPLE_ROMAN:
1518 face->fs.fsCsb[0] |= FS_LATIN1;
1519 break;
1520 case FT_ENCODING_MS_SYMBOL:
1521 face->fs.fsCsb[0] |= FS_SYMBOL;
1522 break;
1523 default:
1524 break;
1529 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1530 have_installed_roman_font = TRUE;
1532 AddFaceToFamily(face, family);
1534 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1536 num_faces = ft_face->num_faces;
1537 pFT_Done_Face(ft_face);
1538 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1539 debugstr_w(StyleW));
1540 } while(num_faces > ++face_index);
1541 return num_faces;
1544 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1546 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1549 static void DumpFontList(void)
1551 Family *family;
1552 Face *face;
1553 struct list *family_elem_ptr, *face_elem_ptr;
1555 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1556 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1557 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1558 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1559 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1560 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1561 if(!face->scalable)
1562 TRACE(" %d", face->size.height);
1563 TRACE("\n");
1566 return;
1569 /***********************************************************
1570 * The replacement list is a way to map an entire font
1571 * family onto another family. For example adding
1573 * [HKCU\Software\Wine\Fonts\Replacements]
1574 * "Wingdings"="Winedings"
1576 * would enumerate the Winedings font both as Winedings and
1577 * Wingdings. However if a real Wingdings font is present the
1578 * replacement does not take place.
1581 static void LoadReplaceList(void)
1583 HKEY hkey;
1584 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1585 LPWSTR value;
1586 LPVOID data;
1587 Family *family;
1588 Face *face;
1589 struct list *family_elem_ptr, *face_elem_ptr;
1590 CHAR familyA[400];
1592 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1593 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1595 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1596 &valuelen, &datalen, NULL, NULL);
1598 valuelen++; /* returned value doesn't include room for '\0' */
1599 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1600 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1602 dlen = datalen;
1603 vlen = valuelen;
1604 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1605 &dlen) == ERROR_SUCCESS) {
1606 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1607 /* "NewName"="Oldname" */
1608 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1610 /* Find the old family and hence all of the font files
1611 in that family */
1612 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1613 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1614 if(!strcmpiW(family->FamilyName, data)) {
1615 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1616 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1617 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1618 debugstr_w(face->StyleName), familyA);
1619 /* Now add a new entry with the new family name */
1620 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1622 break;
1625 /* reset dlen and vlen */
1626 dlen = datalen;
1627 vlen = valuelen;
1629 HeapFree(GetProcessHeap(), 0, data);
1630 HeapFree(GetProcessHeap(), 0, value);
1631 RegCloseKey(hkey);
1635 /*************************************************************
1636 * init_system_links
1638 static BOOL init_system_links(void)
1640 HKEY hkey;
1641 BOOL ret = FALSE;
1642 DWORD type, max_val, max_data, val_len, data_len, index;
1643 WCHAR *value, *data;
1644 WCHAR *entry, *next;
1645 SYSTEM_LINKS *font_link, *system_font_link;
1646 CHILD_FONT *child_font;
1647 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1648 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1649 FONTSIGNATURE fs;
1650 Family *family;
1651 Face *face;
1652 FontSubst *psub;
1654 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1656 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1657 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1658 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1659 val_len = max_val + 1;
1660 data_len = max_data;
1661 index = 0;
1662 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1664 memset(&fs, 0, sizeof(fs));
1665 psub = get_font_subst(&font_subst_list, value, -1);
1666 /* Don't store fonts that are only substitutes for other fonts */
1667 if(psub)
1669 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1670 continue;
1672 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1673 font_link->font_name = strdupW(value);
1674 list_init(&font_link->links);
1675 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1677 WCHAR *face_name;
1678 CHILD_FONT *child_font;
1680 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1682 next = entry + strlenW(entry) + 1;
1684 face_name = strchrW(entry, ',');
1685 if(face_name)
1687 *face_name++ = 0;
1688 while(isspaceW(*face_name))
1689 face_name++;
1691 psub = get_font_subst(&font_subst_list, face_name, -1);
1692 if(psub)
1693 face_name = psub->to.name;
1695 face = find_face_from_filename(entry, face_name);
1696 if(!face)
1698 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1699 continue;
1702 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1703 child_font->face = face;
1704 child_font->font = NULL;
1705 fs.fsCsb[0] |= face->fs.fsCsb[0];
1706 fs.fsCsb[1] |= face->fs.fsCsb[1];
1707 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1708 list_add_tail(&font_link->links, &child_font->entry);
1710 family = find_family_from_name(font_link->font_name);
1711 if(family)
1713 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1715 face->fs_links = fs;
1718 list_add_tail(&system_links, &font_link->entry);
1719 val_len = max_val + 1;
1720 data_len = max_data;
1723 HeapFree(GetProcessHeap(), 0, value);
1724 HeapFree(GetProcessHeap(), 0, data);
1725 RegCloseKey(hkey);
1728 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1729 that Tahoma has */
1731 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1732 system_font_link->font_name = strdupW(System);
1733 list_init(&system_font_link->links);
1735 face = find_face_from_filename(tahoma_ttf, Tahoma);
1736 if(face)
1738 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1739 child_font->face = face;
1740 child_font->font = NULL;
1741 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1742 list_add_tail(&system_font_link->links, &child_font->entry);
1744 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1746 if(!strcmpiW(font_link->font_name, Tahoma))
1748 CHILD_FONT *font_link_entry;
1749 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1751 CHILD_FONT *new_child;
1752 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1753 new_child->face = font_link_entry->face;
1754 new_child->font = NULL;
1755 list_add_tail(&system_font_link->links, &new_child->entry);
1757 break;
1760 list_add_tail(&system_links, &system_font_link->entry);
1761 return ret;
1764 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1766 DIR *dir;
1767 struct dirent *dent;
1768 char path[MAX_PATH];
1770 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1772 dir = opendir(dirname);
1773 if(!dir) {
1774 WARN("Can't open directory %s\n", debugstr_a(dirname));
1775 return FALSE;
1777 while((dent = readdir(dir)) != NULL) {
1778 struct stat statbuf;
1780 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1781 continue;
1783 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1785 sprintf(path, "%s/%s", dirname, dent->d_name);
1787 if(stat(path, &statbuf) == -1)
1789 WARN("Can't stat %s\n", debugstr_a(path));
1790 continue;
1792 if(S_ISDIR(statbuf.st_mode))
1793 ReadFontDir(path, external_fonts);
1794 else
1795 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1797 closedir(dir);
1798 return TRUE;
1801 static void load_fontconfig_fonts(void)
1803 #ifdef SONAME_LIBFONTCONFIG
1804 void *fc_handle = NULL;
1805 FcConfig *config;
1806 FcPattern *pat;
1807 FcObjectSet *os;
1808 FcFontSet *fontset;
1809 int i, len;
1810 char *file;
1811 const char *ext;
1813 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1814 if(!fc_handle) {
1815 TRACE("Wine cannot find the fontconfig library (%s).\n",
1816 SONAME_LIBFONTCONFIG);
1817 return;
1819 #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;}
1820 LOAD_FUNCPTR(FcConfigGetCurrent);
1821 LOAD_FUNCPTR(FcFontList);
1822 LOAD_FUNCPTR(FcFontSetDestroy);
1823 LOAD_FUNCPTR(FcInit);
1824 LOAD_FUNCPTR(FcObjectSetAdd);
1825 LOAD_FUNCPTR(FcObjectSetCreate);
1826 LOAD_FUNCPTR(FcObjectSetDestroy);
1827 LOAD_FUNCPTR(FcPatternCreate);
1828 LOAD_FUNCPTR(FcPatternDestroy);
1829 LOAD_FUNCPTR(FcPatternGetBool);
1830 LOAD_FUNCPTR(FcPatternGetString);
1831 #undef LOAD_FUNCPTR
1833 if(!pFcInit()) return;
1835 config = pFcConfigGetCurrent();
1836 pat = pFcPatternCreate();
1837 os = pFcObjectSetCreate();
1838 pFcObjectSetAdd(os, FC_FILE);
1839 pFcObjectSetAdd(os, FC_SCALABLE);
1840 fontset = pFcFontList(config, pat, os);
1841 if(!fontset) return;
1842 for(i = 0; i < fontset->nfont; i++) {
1843 FcBool scalable;
1845 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1846 continue;
1847 TRACE("fontconfig: %s\n", file);
1849 /* We're just interested in OT/TT fonts for now, so this hack just
1850 picks up the scalable fonts without extensions .pf[ab] to save time
1851 loading every other font */
1853 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1855 TRACE("not scalable\n");
1856 continue;
1859 len = strlen( file );
1860 if(len < 4) continue;
1861 ext = &file[ len - 3 ];
1862 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1863 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1865 pFcFontSetDestroy(fontset);
1866 pFcObjectSetDestroy(os);
1867 pFcPatternDestroy(pat);
1868 sym_not_found:
1869 #endif
1870 return;
1873 static BOOL load_font_from_data_dir(LPCWSTR file)
1875 BOOL ret = FALSE;
1876 const char *data_dir = wine_get_data_dir();
1878 if (!data_dir) data_dir = wine_get_build_dir();
1880 if (data_dir)
1882 INT len;
1883 char *unix_name;
1885 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1887 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1889 strcpy(unix_name, data_dir);
1890 strcat(unix_name, "/fonts/");
1892 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1894 EnterCriticalSection( &freetype_cs );
1895 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1896 LeaveCriticalSection( &freetype_cs );
1897 HeapFree(GetProcessHeap(), 0, unix_name);
1899 return ret;
1902 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1904 static const WCHAR slashW[] = {'\\','\0'};
1905 BOOL ret = FALSE;
1906 WCHAR windowsdir[MAX_PATH];
1907 char *unixname;
1909 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1910 strcatW(windowsdir, fontsW);
1911 strcatW(windowsdir, slashW);
1912 strcatW(windowsdir, file);
1913 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1914 EnterCriticalSection( &freetype_cs );
1915 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1916 LeaveCriticalSection( &freetype_cs );
1917 HeapFree(GetProcessHeap(), 0, unixname);
1919 return ret;
1922 static void load_system_fonts(void)
1924 HKEY hkey;
1925 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1926 const WCHAR * const *value;
1927 DWORD dlen, type;
1928 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1929 char *unixname;
1931 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1932 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1933 strcatW(windowsdir, fontsW);
1934 for(value = SystemFontValues; *value; value++) {
1935 dlen = sizeof(data);
1936 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1937 type == REG_SZ) {
1938 BOOL added = FALSE;
1940 sprintfW(pathW, fmtW, windowsdir, data);
1941 if((unixname = wine_get_unix_file_name(pathW))) {
1942 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1943 HeapFree(GetProcessHeap(), 0, unixname);
1945 if (!added)
1946 load_font_from_data_dir(data);
1949 RegCloseKey(hkey);
1953 /*************************************************************
1955 * This adds registry entries for any externally loaded fonts
1956 * (fonts from fontconfig or FontDirs). It also deletes entries
1957 * of no longer existing fonts.
1960 static void update_reg_entries(void)
1962 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1963 LPWSTR valueW;
1964 DWORD len, len_fam;
1965 Family *family;
1966 Face *face;
1967 struct list *family_elem_ptr, *face_elem_ptr;
1968 WCHAR *file;
1969 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1970 static const WCHAR spaceW[] = {' ', '\0'};
1971 char *path;
1973 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1974 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1975 ERR("Can't create Windows font reg key\n");
1976 goto end;
1979 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1980 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1981 ERR("Can't create Windows font reg key\n");
1982 goto end;
1985 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1986 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1987 ERR("Can't create external font reg key\n");
1988 goto end;
1991 /* enumerate the fonts and add external ones to the two keys */
1993 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1994 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1995 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1996 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1997 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1998 if(!face->external) continue;
1999 len = len_fam;
2000 if (!(face->ntmFlags & NTM_REGULAR))
2001 len = len_fam + strlenW(face->StyleName) + 1;
2002 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2003 strcpyW(valueW, family->FamilyName);
2004 if(len != len_fam) {
2005 strcatW(valueW, spaceW);
2006 strcatW(valueW, face->StyleName);
2008 strcatW(valueW, TrueType);
2010 file = wine_get_dos_file_name(face->file);
2011 if(file)
2012 len = strlenW(file) + 1;
2013 else
2015 if((path = strrchr(face->file, '/')) == NULL)
2016 path = face->file;
2017 else
2018 path++;
2019 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2021 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2022 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2024 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2025 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2026 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2028 HeapFree(GetProcessHeap(), 0, file);
2029 HeapFree(GetProcessHeap(), 0, valueW);
2032 end:
2033 if(external_key) RegCloseKey(external_key);
2034 if(win9x_key) RegCloseKey(win9x_key);
2035 if(winnt_key) RegCloseKey(winnt_key);
2036 return;
2039 static void delete_external_font_keys(void)
2041 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2042 DWORD dlen, vlen, datalen, valuelen, i, type;
2043 LPWSTR valueW;
2044 LPVOID data;
2046 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2047 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2048 ERR("Can't create Windows font reg key\n");
2049 goto end;
2052 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2053 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2054 ERR("Can't create Windows font reg key\n");
2055 goto end;
2058 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2059 ERR("Can't create external font reg key\n");
2060 goto end;
2063 /* Delete all external fonts added last time */
2065 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2066 &valuelen, &datalen, NULL, NULL);
2067 valuelen++; /* returned value doesn't include room for '\0' */
2068 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2069 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2071 dlen = datalen * sizeof(WCHAR);
2072 vlen = valuelen;
2073 i = 0;
2074 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2075 &dlen) == ERROR_SUCCESS) {
2077 RegDeleteValueW(winnt_key, valueW);
2078 RegDeleteValueW(win9x_key, valueW);
2079 /* reset dlen and vlen */
2080 dlen = datalen;
2081 vlen = valuelen;
2083 HeapFree(GetProcessHeap(), 0, data);
2084 HeapFree(GetProcessHeap(), 0, valueW);
2086 /* Delete the old external fonts key */
2087 RegCloseKey(external_key);
2088 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2090 end:
2091 if(win9x_key) RegCloseKey(win9x_key);
2092 if(winnt_key) RegCloseKey(winnt_key);
2095 /*************************************************************
2096 * WineEngAddFontResourceEx
2099 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2101 INT ret = 0;
2103 GDI_CheckNotLock();
2105 if (ft_handle) /* do it only if we have freetype up and running */
2107 char *unixname;
2109 if(flags)
2110 FIXME("Ignoring flags %x\n", flags);
2112 if((unixname = wine_get_unix_file_name(file)))
2114 EnterCriticalSection( &freetype_cs );
2115 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2116 LeaveCriticalSection( &freetype_cs );
2117 HeapFree(GetProcessHeap(), 0, unixname);
2119 if (!ret && !strchrW(file, '\\')) {
2120 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2121 ret = load_font_from_winfonts_dir(file);
2122 if (!ret) {
2123 /* Try in datadir/fonts (or builddir/fonts),
2124 * needed for Magic the Gathering Online
2126 ret = load_font_from_data_dir(file);
2130 return ret;
2133 /*************************************************************
2134 * WineEngAddFontMemResourceEx
2137 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2139 GDI_CheckNotLock();
2141 if (ft_handle) /* do it only if we have freetype up and running */
2143 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2145 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2146 memcpy(pFontCopy, pbFont, cbFont);
2148 EnterCriticalSection( &freetype_cs );
2149 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2150 LeaveCriticalSection( &freetype_cs );
2152 if (*pcFonts == 0)
2154 TRACE("AddFontToList failed\n");
2155 HeapFree(GetProcessHeap(), 0, pFontCopy);
2156 return NULL;
2158 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2159 * For now return something unique but quite random
2161 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2162 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2165 *pcFonts = 0;
2166 return 0;
2169 /*************************************************************
2170 * WineEngRemoveFontResourceEx
2173 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2175 GDI_CheckNotLock();
2176 FIXME(":stub\n");
2177 return TRUE;
2180 static const struct nls_update_font_list
2182 UINT ansi_cp, oem_cp;
2183 const char *oem, *fixed, *system;
2184 const char *courier, *serif, *small, *sserif;
2185 /* these are for font substitutes */
2186 const char *shelldlg, *tmsrmn;
2187 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2188 *helv_0, *tmsrmn_0;
2189 const struct subst
2191 const char *from, *to;
2192 } arial_0, courier_new_0, times_new_roman_0;
2193 } nls_update_font_list[] =
2195 /* Latin 1 (United States) */
2196 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2197 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2198 "Tahoma","Times New Roman",
2199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2200 { 0 }, { 0 }, { 0 }
2202 /* Latin 1 (Multilingual) */
2203 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2204 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2207 { 0 }, { 0 }, { 0 }
2209 /* Eastern Europe */
2210 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2211 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2212 "Tahoma","Times New Roman", /* FIXME unverified */
2213 "Fixedsys,238", "System,238",
2214 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2215 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2216 { "Arial CE,0", "Arial,238" },
2217 { "Courier New CE,0", "Courier New,238" },
2218 { "Times New Roman CE,0", "Times New Roman,238" }
2220 /* Cyrillic */
2221 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2222 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2223 "Tahoma","Times New Roman", /* FIXME unverified */
2224 "Fixedsys,204", "System,204",
2225 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2226 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2227 { "Arial Cyr,0", "Arial,204" },
2228 { "Courier New Cyr,0", "Courier New,204" },
2229 { "Times New Roman Cyr,0", "Times New Roman,204" }
2231 /* Greek */
2232 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2233 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2234 "Tahoma","Times New Roman", /* FIXME unverified */
2235 "Fixedsys,161", "System,161",
2236 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2237 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2238 { "Arial Greek,0", "Arial,161" },
2239 { "Courier New Greek,0", "Courier New,161" },
2240 { "Times New Roman Greek,0", "Times New Roman,161" }
2242 /* Turkish */
2243 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2244 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,162", "System,162",
2247 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2248 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2249 { "Arial Tur,0", "Arial,162" },
2250 { "Courier New Tur,0", "Courier New,162" },
2251 { "Times New Roman Tur,0", "Times New Roman,162" }
2253 /* Hebrew */
2254 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2255 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 "Fixedsys,177", "System,177",
2258 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2259 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2260 { 0 }, { 0 }, { 0 }
2262 /* Arabic */
2263 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2264 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2265 "Tahoma","Times New Roman", /* FIXME unverified */
2266 "Fixedsys,178", "System,178",
2267 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2268 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2269 { 0 }, { 0 }, { 0 }
2271 /* Baltic */
2272 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2273 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2274 "Tahoma","Times New Roman", /* FIXME unverified */
2275 "Fixedsys,186", "System,186",
2276 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2277 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2278 { "Arial Baltic,0", "Arial,186" },
2279 { "Courier New Baltic,0", "Courier New,186" },
2280 { "Times New Roman Baltic,0", "Times New Roman,186" }
2282 /* Vietnamese */
2283 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2284 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2285 "Tahoma","Times New Roman", /* FIXME unverified */
2286 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2287 { 0 }, { 0 }, { 0 }
2289 /* Thai */
2290 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2291 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2292 "Tahoma","Times New Roman", /* FIXME unverified */
2293 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2294 { 0 }, { 0 }, { 0 }
2296 /* Japanese */
2297 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2298 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2299 "MS UI Gothic","MS Serif",
2300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2301 { 0 }, { 0 }, { 0 }
2303 /* Chinese Simplified */
2304 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2306 "SimSun", "NSimSun",
2307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2308 { 0 }, { 0 }, { 0 }
2310 /* Korean */
2311 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2312 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2313 "Gulim", "Batang",
2314 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2315 { 0 }, { 0 }, { 0 }
2317 /* Chinese Traditional */
2318 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2319 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2320 "PMingLiU", "MingLiU",
2321 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2322 { 0 }, { 0 }, { 0 }
2326 static const WCHAR *font_links_list[] =
2328 Lucida_Sans_Unicode,
2329 Microsoft_Sans_Serif,
2330 Tahoma
2333 static const struct font_links_defaults_list
2335 /* Keyed off substitution for "MS Shell Dlg" */
2336 const WCHAR *shelldlg;
2337 /* Maximum of four substitutes, plus terminating NULL pointer */
2338 const WCHAR *substitutes[5];
2339 } font_links_defaults_list[] =
2341 /* Non East-Asian */
2342 { Tahoma, /* FIXME unverified ordering */
2343 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2345 /* Below lists are courtesy of
2346 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2348 /* Japanese */
2349 { MS_UI_Gothic,
2350 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2352 /* Chinese Simplified */
2353 { SimSun,
2354 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2356 /* Korean */
2357 { Gulim,
2358 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2360 /* Chinese Traditional */
2361 { PMingLiU,
2362 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2366 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2368 return ( ansi_cp == 932 /* CP932 for Japanese */
2369 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2370 || ansi_cp == 949 /* CP949 for Korean */
2371 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2374 static inline HKEY create_fonts_NT_registry_key(void)
2376 HKEY hkey = 0;
2378 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2379 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2380 return hkey;
2383 static inline HKEY create_fonts_9x_registry_key(void)
2385 HKEY hkey = 0;
2387 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2388 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2389 return hkey;
2392 static inline HKEY create_config_fonts_registry_key(void)
2394 HKEY hkey = 0;
2396 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2397 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2398 return hkey;
2401 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2403 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2404 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2405 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2406 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2409 static void set_value_key(HKEY hkey, const char *name, const char *value)
2411 if (value)
2412 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2413 else if (name)
2414 RegDeleteValueA(hkey, name);
2417 static void update_font_info(void)
2419 char buf[40], cpbuf[40];
2420 DWORD len, type;
2421 HKEY hkey = 0;
2422 UINT i, ansi_cp = 0, oem_cp = 0;
2423 BOOL done = FALSE;
2425 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2426 return;
2428 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2429 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2430 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2431 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2432 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2434 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2435 if (is_dbcs_ansi_cp(ansi_cp))
2436 use_default_fallback = TRUE;
2438 len = sizeof(buf);
2439 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2441 if (!strcmp( buf, cpbuf )) /* already set correctly */
2443 RegCloseKey(hkey);
2444 return;
2446 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2448 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2450 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2451 RegCloseKey(hkey);
2453 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2455 HKEY hkey;
2457 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2458 nls_update_font_list[i].oem_cp == oem_cp)
2460 hkey = create_config_fonts_registry_key();
2461 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2462 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2463 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2464 RegCloseKey(hkey);
2466 hkey = create_fonts_NT_registry_key();
2467 add_font_list(hkey, &nls_update_font_list[i]);
2468 RegCloseKey(hkey);
2470 hkey = create_fonts_9x_registry_key();
2471 add_font_list(hkey, &nls_update_font_list[i]);
2472 RegCloseKey(hkey);
2474 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2476 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2477 strlen(nls_update_font_list[i].shelldlg)+1);
2478 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2479 strlen(nls_update_font_list[i].tmsrmn)+1);
2481 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2482 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2483 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2484 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2485 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2486 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2487 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2488 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2490 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2491 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2492 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2494 RegCloseKey(hkey);
2496 done = TRUE;
2498 else
2500 /* Delete the FontSubstitutes from other locales */
2501 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2503 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2504 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2505 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2506 RegCloseKey(hkey);
2510 if (!done)
2511 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2513 /* Clear out system links */
2514 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2517 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2519 const WCHAR *value;
2520 int i;
2521 FontSubst *psub;
2522 Family *family;
2523 Face *face;
2524 const char *file;
2525 WCHAR *fileW;
2526 int fileLen;
2527 WCHAR buff[MAX_PATH];
2528 WCHAR *data;
2529 int entryLen;
2531 static const WCHAR comma[] = {',',0};
2533 RegDeleteValueW(hkey, name);
2534 if (values)
2536 data = buff;
2537 data[0] = '\0';
2538 for (i = 0; values[i] != NULL; i++)
2540 value = values[i];
2541 if (!strcmpiW(name,value))
2542 continue;
2543 psub = get_font_subst(&font_subst_list, value, -1);
2544 if(psub)
2545 value = psub->to.name;
2546 family = find_family_from_name(value);
2547 if (!family)
2548 continue;
2549 file = NULL;
2550 /* Use first extant filename for this Family */
2551 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2553 if (!face->file)
2554 continue;
2555 file = strrchr(face->file, '/');
2556 if (!file)
2557 file = face->file;
2558 else
2559 file++;
2560 break;
2562 if (!file)
2563 continue;
2564 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2565 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2566 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2567 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2568 if (sizeof(buff)-(data-buff) < entryLen + 1)
2570 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2571 HeapFree(GetProcessHeap(), 0, fileW);
2572 break;
2574 strcpyW(data, fileW);
2575 strcatW(data, comma);
2576 strcatW(data, value);
2577 data += entryLen;
2578 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2579 HeapFree(GetProcessHeap(), 0, fileW);
2581 if (data != buff)
2583 *data='\0';
2584 data++;
2585 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2586 } else
2587 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2588 } else
2589 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2592 static void update_system_links(void)
2594 HKEY hkey = 0;
2595 UINT i, j;
2596 BOOL done = FALSE;
2597 DWORD disposition;
2598 FontSubst *psub;
2600 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2602 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2604 if (disposition == REG_OPENED_EXISTING_KEY)
2606 TRACE("SystemLink key already exists, doing nothing\n");
2607 RegCloseKey(hkey);
2608 return;
2611 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2612 if (!psub) {
2613 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2614 RegCloseKey(hkey);
2615 return;
2618 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2620 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2622 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2623 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2625 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2626 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2627 done = TRUE;
2629 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2631 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2634 RegCloseKey(hkey);
2635 if (!done)
2636 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2637 } else
2638 WARN("failed to create SystemLink key\n");
2642 static BOOL init_freetype(void)
2644 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2645 if(!ft_handle) {
2646 WINE_MESSAGE(
2647 "Wine cannot find the FreeType font library. To enable Wine to\n"
2648 "use TrueType fonts please install a version of FreeType greater than\n"
2649 "or equal to 2.0.5.\n"
2650 "http://www.freetype.org\n");
2651 return FALSE;
2654 #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;}
2656 LOAD_FUNCPTR(FT_Vector_Unit)
2657 LOAD_FUNCPTR(FT_Done_Face)
2658 LOAD_FUNCPTR(FT_Get_Char_Index)
2659 LOAD_FUNCPTR(FT_Get_Module)
2660 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2661 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2662 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2663 LOAD_FUNCPTR(FT_Init_FreeType)
2664 LOAD_FUNCPTR(FT_Load_Glyph)
2665 LOAD_FUNCPTR(FT_Matrix_Multiply)
2666 #ifndef FT_MULFIX_INLINED
2667 LOAD_FUNCPTR(FT_MulFix)
2668 #endif
2669 LOAD_FUNCPTR(FT_New_Face)
2670 LOAD_FUNCPTR(FT_New_Memory_Face)
2671 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2672 LOAD_FUNCPTR(FT_Outline_Transform)
2673 LOAD_FUNCPTR(FT_Outline_Translate)
2674 LOAD_FUNCPTR(FT_Select_Charmap)
2675 LOAD_FUNCPTR(FT_Set_Charmap)
2676 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2677 LOAD_FUNCPTR(FT_Vector_Transform)
2678 LOAD_FUNCPTR(FT_Render_Glyph)
2680 #undef LOAD_FUNCPTR
2681 /* Don't warn if these ones are missing */
2682 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2683 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2684 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2685 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2686 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2687 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2688 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2689 #endif
2690 #ifdef HAVE_FREETYPE_FTWINFNT_H
2691 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2692 #endif
2693 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2694 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2695 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2696 <= 2.0.3 has FT_Sqrt64 */
2697 goto sym_not_found;
2700 if(pFT_Init_FreeType(&library) != 0) {
2701 ERR("Can't init FreeType library\n");
2702 wine_dlclose(ft_handle, NULL, 0);
2703 ft_handle = NULL;
2704 return FALSE;
2706 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2707 if (pFT_Library_Version)
2708 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2710 if (FT_Version.major<=0)
2712 FT_Version.major=2;
2713 FT_Version.minor=0;
2714 FT_Version.patch=5;
2716 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2717 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2718 ((FT_Version.minor << 8) & 0x00ff00) |
2719 ((FT_Version.patch ) & 0x0000ff);
2721 return TRUE;
2723 sym_not_found:
2724 WINE_MESSAGE(
2725 "Wine cannot find certain functions that it needs inside the FreeType\n"
2726 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2727 "FreeType to at least version 2.0.5.\n"
2728 "http://www.freetype.org\n");
2729 wine_dlclose(ft_handle, NULL, 0);
2730 ft_handle = NULL;
2731 return FALSE;
2734 /*************************************************************
2735 * WineEngInit
2737 * Initialize FreeType library and create a list of available faces
2739 BOOL WineEngInit(void)
2741 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2742 static const WCHAR pathW[] = {'P','a','t','h',0};
2743 HKEY hkey;
2744 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2745 WCHAR windowsdir[MAX_PATH];
2746 char *unixname;
2747 HANDLE font_mutex;
2748 const char *data_dir;
2750 TRACE("\n");
2752 /* update locale dependent font info in registry */
2753 update_font_info();
2755 if(!init_freetype()) return FALSE;
2757 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2758 ERR("Failed to create font mutex\n");
2759 return FALSE;
2761 WaitForSingleObject(font_mutex, INFINITE);
2763 delete_external_font_keys();
2765 /* load the system bitmap fonts */
2766 load_system_fonts();
2768 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2769 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2770 strcatW(windowsdir, fontsW);
2771 if((unixname = wine_get_unix_file_name(windowsdir)))
2773 ReadFontDir(unixname, FALSE);
2774 HeapFree(GetProcessHeap(), 0, unixname);
2777 /* load the system truetype fonts */
2778 data_dir = wine_get_data_dir();
2779 if (!data_dir) data_dir = wine_get_build_dir();
2780 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2781 strcpy(unixname, data_dir);
2782 strcat(unixname, "/fonts/");
2783 ReadFontDir(unixname, TRUE);
2784 HeapFree(GetProcessHeap(), 0, unixname);
2787 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2788 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2789 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2790 will skip these. */
2791 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2792 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2793 &hkey) == ERROR_SUCCESS) {
2794 LPWSTR data, valueW;
2795 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2796 &valuelen, &datalen, NULL, NULL);
2798 valuelen++; /* returned value doesn't include room for '\0' */
2799 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2800 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2801 if (valueW && data)
2803 dlen = datalen * sizeof(WCHAR);
2804 vlen = valuelen;
2805 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2806 &dlen) == ERROR_SUCCESS) {
2807 if(data[0] && (data[1] == ':'))
2809 if((unixname = wine_get_unix_file_name(data)))
2811 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2812 HeapFree(GetProcessHeap(), 0, unixname);
2815 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2817 WCHAR pathW[MAX_PATH];
2818 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2819 BOOL added = FALSE;
2821 sprintfW(pathW, fmtW, windowsdir, data);
2822 if((unixname = wine_get_unix_file_name(pathW)))
2824 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2825 HeapFree(GetProcessHeap(), 0, unixname);
2827 if (!added)
2828 load_font_from_data_dir(data);
2830 /* reset dlen and vlen */
2831 dlen = datalen;
2832 vlen = valuelen;
2835 HeapFree(GetProcessHeap(), 0, data);
2836 HeapFree(GetProcessHeap(), 0, valueW);
2837 RegCloseKey(hkey);
2840 load_fontconfig_fonts();
2842 /* then look in any directories that we've specified in the config file */
2843 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2844 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2846 DWORD len;
2847 LPWSTR valueW;
2848 LPSTR valueA, ptr;
2850 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2852 len += sizeof(WCHAR);
2853 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2854 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2856 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2857 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2858 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2859 TRACE( "got font path %s\n", debugstr_a(valueA) );
2860 ptr = valueA;
2861 while (ptr)
2863 LPSTR next = strchr( ptr, ':' );
2864 if (next) *next++ = 0;
2865 ReadFontDir( ptr, TRUE );
2866 ptr = next;
2868 HeapFree( GetProcessHeap(), 0, valueA );
2870 HeapFree( GetProcessHeap(), 0, valueW );
2872 RegCloseKey(hkey);
2875 DumpFontList();
2876 LoadSubstList();
2877 DumpSubstList();
2878 LoadReplaceList();
2879 update_reg_entries();
2881 update_system_links();
2882 init_system_links();
2884 ReleaseMutex(font_mutex);
2885 return TRUE;
2889 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2891 TT_OS2 *pOS2;
2892 TT_HoriHeader *pHori;
2894 LONG ppem;
2896 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2897 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2899 if(height == 0) height = 16;
2901 /* Calc. height of EM square:
2903 * For +ve lfHeight we have
2904 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2905 * Re-arranging gives:
2906 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2908 * For -ve lfHeight we have
2909 * |lfHeight| = ppem
2910 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2911 * with il = winAscent + winDescent - units_per_em]
2915 if(height > 0) {
2916 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2917 ppem = MulDiv(ft_face->units_per_EM, height,
2918 pHori->Ascender - pHori->Descender);
2919 else
2920 ppem = MulDiv(ft_face->units_per_EM, height,
2921 pOS2->usWinAscent + pOS2->usWinDescent);
2923 else
2924 ppem = -height;
2926 return ppem;
2929 static struct font_mapping *map_font_file( const char *name )
2931 struct font_mapping *mapping;
2932 struct stat st;
2933 int fd;
2935 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2936 if (fstat( fd, &st ) == -1) goto error;
2938 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2940 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2942 mapping->refcount++;
2943 close( fd );
2944 return mapping;
2947 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2948 goto error;
2950 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2951 close( fd );
2953 if (mapping->data == MAP_FAILED)
2955 HeapFree( GetProcessHeap(), 0, mapping );
2956 return NULL;
2958 mapping->refcount = 1;
2959 mapping->dev = st.st_dev;
2960 mapping->ino = st.st_ino;
2961 mapping->size = st.st_size;
2962 list_add_tail( &mappings_list, &mapping->entry );
2963 return mapping;
2965 error:
2966 close( fd );
2967 return NULL;
2970 static void unmap_font_file( struct font_mapping *mapping )
2972 if (!--mapping->refcount)
2974 list_remove( &mapping->entry );
2975 munmap( mapping->data, mapping->size );
2976 HeapFree( GetProcessHeap(), 0, mapping );
2980 static LONG load_VDMX(GdiFont*, LONG);
2982 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2984 FT_Error err;
2985 FT_Face ft_face;
2986 void *data_ptr;
2987 DWORD data_size;
2989 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2991 if (face->file)
2993 if (!(font->mapping = map_font_file( face->file )))
2995 WARN("failed to map %s\n", debugstr_a(face->file));
2996 return 0;
2998 data_ptr = font->mapping->data;
2999 data_size = font->mapping->size;
3001 else
3003 data_ptr = face->font_data_ptr;
3004 data_size = face->font_data_size;
3007 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3008 if(err) {
3009 ERR("FT_New_Face rets %d\n", err);
3010 return 0;
3013 /* set it here, as load_VDMX needs it */
3014 font->ft_face = ft_face;
3016 if(FT_IS_SCALABLE(ft_face)) {
3017 /* load the VDMX table if we have one */
3018 font->ppem = load_VDMX(font, height);
3019 if(font->ppem == 0)
3020 font->ppem = calc_ppem_for_height(ft_face, height);
3021 TRACE("height %d => ppem %d\n", height, font->ppem);
3023 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3024 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3025 } else {
3026 font->ppem = height;
3027 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3028 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3030 return ft_face;
3034 static int get_nearest_charset(Face *face, int *cp)
3036 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3037 a single face with the requested charset. The idea is to check if
3038 the selected font supports the current ANSI codepage, if it does
3039 return the corresponding charset, else return the first charset */
3041 CHARSETINFO csi;
3042 int acp = GetACP(), i;
3043 DWORD fs0;
3045 *cp = acp;
3046 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3047 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3048 return csi.ciCharset;
3050 for(i = 0; i < 32; i++) {
3051 fs0 = 1L << i;
3052 if(face->fs.fsCsb[0] & fs0) {
3053 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3054 *cp = csi.ciACP;
3055 return csi.ciCharset;
3057 else
3058 FIXME("TCI failing on %x\n", fs0);
3062 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3063 face->fs.fsCsb[0], face->file);
3064 *cp = acp;
3065 return DEFAULT_CHARSET;
3068 static GdiFont *alloc_font(void)
3070 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3071 ret->gmsize = 1;
3072 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3073 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3074 ret->potm = NULL;
3075 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3076 ret->total_kern_pairs = (DWORD)-1;
3077 ret->kern_pairs = NULL;
3078 list_init(&ret->hfontlist);
3079 list_init(&ret->child_fonts);
3080 return ret;
3083 static void free_font(GdiFont *font)
3085 struct list *cursor, *cursor2;
3086 DWORD i;
3088 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3090 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3091 struct list *first_hfont;
3092 HFONTLIST *hfontlist;
3093 list_remove(cursor);
3094 if(child->font)
3096 first_hfont = list_head(&child->font->hfontlist);
3097 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3098 DeleteObject(hfontlist->hfont);
3099 HeapFree(GetProcessHeap(), 0, hfontlist);
3100 free_font(child->font);
3102 HeapFree(GetProcessHeap(), 0, child);
3105 if (font->ft_face) pFT_Done_Face(font->ft_face);
3106 if (font->mapping) unmap_font_file( font->mapping );
3107 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3108 HeapFree(GetProcessHeap(), 0, font->potm);
3109 HeapFree(GetProcessHeap(), 0, font->name);
3110 for (i = 0; i < font->gmsize; i++)
3111 HeapFree(GetProcessHeap(),0,font->gm[i]);
3112 HeapFree(GetProcessHeap(), 0, font->gm);
3113 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3114 HeapFree(GetProcessHeap(), 0, font);
3118 /*************************************************************
3119 * load_VDMX
3121 * load the vdmx entry for the specified height
3124 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3125 ( ( (FT_ULong)_x4 << 24 ) | \
3126 ( (FT_ULong)_x3 << 16 ) | \
3127 ( (FT_ULong)_x2 << 8 ) | \
3128 (FT_ULong)_x1 )
3130 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3132 typedef struct {
3133 BYTE bCharSet;
3134 BYTE xRatio;
3135 BYTE yStartRatio;
3136 BYTE yEndRatio;
3137 } Ratios;
3139 typedef struct {
3140 WORD recs;
3141 BYTE startsz;
3142 BYTE endsz;
3143 } VDMX_group;
3145 static LONG load_VDMX(GdiFont *font, LONG height)
3147 WORD hdr[3], tmp;
3148 VDMX_group group;
3149 BYTE devXRatio, devYRatio;
3150 USHORT numRecs, numRatios;
3151 DWORD result, offset = -1;
3152 LONG ppem = 0;
3153 int i;
3155 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3157 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3158 return ppem;
3160 /* FIXME: need the real device aspect ratio */
3161 devXRatio = 1;
3162 devYRatio = 1;
3164 numRecs = GET_BE_WORD(hdr[1]);
3165 numRatios = GET_BE_WORD(hdr[2]);
3167 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3168 for(i = 0; i < numRatios; i++) {
3169 Ratios ratio;
3171 offset = (3 * 2) + (i * sizeof(Ratios));
3172 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3173 offset = -1;
3175 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3177 if((ratio.xRatio == 0 &&
3178 ratio.yStartRatio == 0 &&
3179 ratio.yEndRatio == 0) ||
3180 (devXRatio == ratio.xRatio &&
3181 devYRatio >= ratio.yStartRatio &&
3182 devYRatio <= ratio.yEndRatio))
3184 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3185 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3186 offset = GET_BE_WORD(tmp);
3187 break;
3191 if(offset == -1) {
3192 FIXME("No suitable ratio found\n");
3193 return ppem;
3196 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3197 USHORT recs;
3198 BYTE startsz, endsz;
3199 WORD *vTable;
3201 recs = GET_BE_WORD(group.recs);
3202 startsz = group.startsz;
3203 endsz = group.endsz;
3205 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3207 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3208 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3209 if(result == GDI_ERROR) {
3210 FIXME("Failed to retrieve vTable\n");
3211 goto end;
3214 if(height > 0) {
3215 for(i = 0; i < recs; i++) {
3216 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3217 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3218 ppem = GET_BE_WORD(vTable[i * 3]);
3220 if(yMax + -yMin == height) {
3221 font->yMax = yMax;
3222 font->yMin = yMin;
3223 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3224 break;
3226 if(yMax + -yMin > height) {
3227 if(--i < 0) {
3228 ppem = 0;
3229 goto end; /* failed */
3231 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3232 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3233 ppem = GET_BE_WORD(vTable[i * 3]);
3234 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3235 break;
3238 if(!font->yMax) {
3239 ppem = 0;
3240 TRACE("ppem not found for height %d\n", height);
3242 } else {
3243 ppem = -height;
3244 if(ppem < startsz || ppem > endsz)
3245 goto end;
3247 for(i = 0; i < recs; i++) {
3248 USHORT yPelHeight;
3249 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3251 if(yPelHeight > ppem)
3252 break; /* failed */
3254 if(yPelHeight == ppem) {
3255 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3256 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3257 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3258 break;
3262 end:
3263 HeapFree(GetProcessHeap(), 0, vTable);
3266 return ppem;
3269 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3271 if(font->font_desc.hash != fd->hash) return TRUE;
3272 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3273 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3274 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3275 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3278 static void calc_hash(FONT_DESC *pfd)
3280 DWORD hash = 0, *ptr, two_chars;
3281 WORD *pwc;
3282 unsigned int i;
3284 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3285 hash ^= *ptr;
3286 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3287 hash ^= *ptr;
3288 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3289 two_chars = *ptr;
3290 pwc = (WCHAR *)&two_chars;
3291 if(!*pwc) break;
3292 *pwc = toupperW(*pwc);
3293 pwc++;
3294 *pwc = toupperW(*pwc);
3295 hash ^= two_chars;
3296 if(!*pwc) break;
3298 hash ^= !pfd->can_use_bitmap;
3299 pfd->hash = hash;
3300 return;
3303 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3305 GdiFont *ret;
3306 FONT_DESC fd;
3307 HFONTLIST *hflist;
3308 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3310 fd.lf = *plf;
3311 fd.matrix = *pmat;
3312 fd.can_use_bitmap = can_use_bitmap;
3313 calc_hash(&fd);
3315 /* try the child list */
3316 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3317 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3318 if(!fontcmp(ret, &fd)) {
3319 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3320 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3321 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3322 if(hflist->hfont == hfont)
3323 return ret;
3328 /* try the in-use list */
3329 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3330 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3331 if(!fontcmp(ret, &fd)) {
3332 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3333 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3334 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3335 if(hflist->hfont == hfont)
3336 return ret;
3338 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3339 hflist->hfont = hfont;
3340 list_add_head(&ret->hfontlist, &hflist->entry);
3341 return ret;
3345 /* then the unused list */
3346 font_elem_ptr = list_head(&unused_gdi_font_list);
3347 while(font_elem_ptr) {
3348 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3349 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3350 if(!fontcmp(ret, &fd)) {
3351 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3352 assert(list_empty(&ret->hfontlist));
3353 TRACE("Found %p in unused list\n", ret);
3354 list_remove(&ret->entry);
3355 list_add_head(&gdi_font_list, &ret->entry);
3356 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3357 hflist->hfont = hfont;
3358 list_add_head(&ret->hfontlist, &hflist->entry);
3359 return ret;
3362 return NULL;
3365 static void add_to_cache(GdiFont *font)
3367 static DWORD cache_num = 1;
3369 font->cache_num = cache_num++;
3370 list_add_head(&gdi_font_list, &font->entry);
3373 /*************************************************************
3374 * create_child_font_list
3376 static BOOL create_child_font_list(GdiFont *font)
3378 BOOL ret = FALSE;
3379 SYSTEM_LINKS *font_link;
3380 CHILD_FONT *font_link_entry, *new_child;
3381 FontSubst *psub;
3382 WCHAR* font_name;
3384 psub = get_font_subst(&font_subst_list, font->name, -1);
3385 font_name = psub ? psub->to.name : font->name;
3386 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3388 if(!strcmpiW(font_link->font_name, font_name))
3390 TRACE("found entry in system list\n");
3391 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3393 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3394 new_child->face = font_link_entry->face;
3395 new_child->font = NULL;
3396 list_add_tail(&font->child_fonts, &new_child->entry);
3397 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3399 ret = TRUE;
3400 break;
3404 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3405 * Sans Serif. This is how asian windows get default fallbacks for fonts
3407 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3408 font->charset != OEM_CHARSET &&
3409 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3410 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3412 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3414 TRACE("found entry in default fallback list\n");
3415 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3417 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3418 new_child->face = font_link_entry->face;
3419 new_child->font = NULL;
3420 list_add_tail(&font->child_fonts, &new_child->entry);
3421 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3423 ret = TRUE;
3424 break;
3428 return ret;
3431 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3433 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3435 if (pFT_Set_Charmap)
3437 FT_Int i;
3438 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3440 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3442 for (i = 0; i < ft_face->num_charmaps; i++)
3444 if (ft_face->charmaps[i]->encoding == encoding)
3446 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3447 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3449 switch (ft_face->charmaps[i]->platform_id)
3451 default:
3452 cmap_def = ft_face->charmaps[i];
3453 break;
3454 case 0: /* Apple Unicode */
3455 cmap0 = ft_face->charmaps[i];
3456 break;
3457 case 1: /* Macintosh */
3458 cmap1 = ft_face->charmaps[i];
3459 break;
3460 case 2: /* ISO */
3461 cmap2 = ft_face->charmaps[i];
3462 break;
3463 case 3: /* Microsoft */
3464 cmap3 = ft_face->charmaps[i];
3465 break;
3469 if (cmap3) /* prefer Microsoft cmap table */
3470 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3471 else if (cmap1)
3472 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3473 else if (cmap2)
3474 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3475 else if (cmap0)
3476 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3477 else if (cmap_def)
3478 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3480 return ft_err == FT_Err_Ok;
3483 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3486 /*************************************************************
3487 * WineEngCreateFontInstance
3490 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3492 GdiFont *ret;
3493 Face *face, *best, *best_bitmap;
3494 Family *family, *last_resort_family;
3495 struct list *family_elem_ptr, *face_elem_ptr;
3496 INT height, width = 0;
3497 unsigned int score = 0, new_score;
3498 signed int diff = 0, newdiff;
3499 BOOL bd, it, can_use_bitmap;
3500 LOGFONTW lf;
3501 CHARSETINFO csi;
3502 HFONTLIST *hflist;
3503 FMAT2 dcmat;
3504 FontSubst *psub = NULL;
3506 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3507 lf.lfWidth = abs(lf.lfWidth);
3509 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3511 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3512 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3513 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3514 lf.lfEscapement);
3516 if(dc->GraphicsMode == GM_ADVANCED)
3517 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3518 else
3520 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3521 font scaling abilities. */
3522 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3523 dcmat.eM21 = dcmat.eM12 = 0;
3526 /* Try to avoid not necessary glyph transformations */
3527 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3529 lf.lfHeight *= fabs(dcmat.eM11);
3530 lf.lfWidth *= fabs(dcmat.eM11);
3531 dcmat.eM11 = dcmat.eM22 = 1.0;
3534 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3535 dcmat.eM21, dcmat.eM22);
3537 GDI_CheckNotLock();
3538 EnterCriticalSection( &freetype_cs );
3540 /* check the cache first */
3541 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3542 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3543 LeaveCriticalSection( &freetype_cs );
3544 return ret;
3547 TRACE("not in cache\n");
3548 if(list_empty(&font_list)) /* No fonts installed */
3550 TRACE("No fonts installed\n");
3551 LeaveCriticalSection( &freetype_cs );
3552 return NULL;
3554 if(!have_installed_roman_font)
3556 TRACE("No roman font installed\n");
3557 LeaveCriticalSection( &freetype_cs );
3558 return NULL;
3561 ret = alloc_font();
3563 ret->font_desc.matrix = dcmat;
3564 ret->font_desc.lf = lf;
3565 ret->font_desc.can_use_bitmap = can_use_bitmap;
3566 calc_hash(&ret->font_desc);
3567 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3568 hflist->hfont = hfont;
3569 list_add_head(&ret->hfontlist, &hflist->entry);
3571 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3572 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3573 original value lfCharSet. Note this is a special case for
3574 Symbol and doesn't happen at least for "Wingdings*" */
3576 if(!strcmpiW(lf.lfFaceName, SymbolW))
3577 lf.lfCharSet = SYMBOL_CHARSET;
3579 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3580 switch(lf.lfCharSet) {
3581 case DEFAULT_CHARSET:
3582 csi.fs.fsCsb[0] = 0;
3583 break;
3584 default:
3585 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3586 csi.fs.fsCsb[0] = 0;
3587 break;
3591 family = NULL;
3592 if(lf.lfFaceName[0] != '\0') {
3593 SYSTEM_LINKS *font_link;
3594 CHILD_FONT *font_link_entry;
3595 LPWSTR FaceName = lf.lfFaceName;
3598 * Check for a leading '@' this signals that the font is being
3599 * requested in tategaki mode (vertical writing substitution) but
3600 * does not affect the fontface that is to be selected.
3602 if (lf.lfFaceName[0]=='@')
3603 FaceName = &lf.lfFaceName[1];
3605 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3607 if(psub) {
3608 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3609 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3610 if (psub->to.charset != -1)
3611 lf.lfCharSet = psub->to.charset;
3614 /* We want a match on name and charset or just name if
3615 charset was DEFAULT_CHARSET. If the latter then
3616 we fixup the returned charset later in get_nearest_charset
3617 where we'll either use the charset of the current ansi codepage
3618 or if that's unavailable the first charset that the font supports.
3620 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3621 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3622 if (!strcmpiW(family->FamilyName, FaceName) ||
3623 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3625 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3626 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3627 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3628 if(face->scalable || can_use_bitmap)
3629 goto found;
3635 * Try check the SystemLink list first for a replacement font.
3636 * We may find good replacements there.
3638 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3640 if(!strcmpiW(font_link->font_name, FaceName) ||
3641 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3643 TRACE("found entry in system list\n");
3644 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3646 face = font_link_entry->face;
3647 family = face->family;
3648 if(csi.fs.fsCsb[0] &
3649 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3651 if(face->scalable || can_use_bitmap)
3652 goto found;
3659 psub = NULL; /* substitution is no more relevant */
3661 /* If requested charset was DEFAULT_CHARSET then try using charset
3662 corresponding to the current ansi codepage */
3663 if (!csi.fs.fsCsb[0])
3665 INT acp = GetACP();
3666 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3667 FIXME("TCI failed on codepage %d\n", acp);
3668 csi.fs.fsCsb[0] = 0;
3669 } else
3670 lf.lfCharSet = csi.ciCharset;
3673 /* Face families are in the top 4 bits of lfPitchAndFamily,
3674 so mask with 0xF0 before testing */
3676 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3677 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3678 strcpyW(lf.lfFaceName, defFixed);
3679 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3680 strcpyW(lf.lfFaceName, defSerif);
3681 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3682 strcpyW(lf.lfFaceName, defSans);
3683 else
3684 strcpyW(lf.lfFaceName, defSans);
3685 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3686 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3687 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3688 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3689 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3690 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3691 if(face->scalable || can_use_bitmap)
3692 goto found;
3697 last_resort_family = NULL;
3698 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3699 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3700 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3701 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3702 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3703 if(face->scalable)
3704 goto found;
3705 if(can_use_bitmap && !last_resort_family)
3706 last_resort_family = family;
3711 if(last_resort_family) {
3712 family = last_resort_family;
3713 csi.fs.fsCsb[0] = 0;
3714 goto found;
3717 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3718 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3719 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3720 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3721 if(face->scalable) {
3722 csi.fs.fsCsb[0] = 0;
3723 WARN("just using first face for now\n");
3724 goto found;
3726 if(can_use_bitmap && !last_resort_family)
3727 last_resort_family = family;
3730 if(!last_resort_family) {
3731 FIXME("can't find a single appropriate font - bailing\n");
3732 free_font(ret);
3733 LeaveCriticalSection( &freetype_cs );
3734 return NULL;
3737 WARN("could only find a bitmap font - this will probably look awful!\n");
3738 family = last_resort_family;
3739 csi.fs.fsCsb[0] = 0;
3741 found:
3742 it = lf.lfItalic ? 1 : 0;
3743 bd = lf.lfWeight > 550 ? 1 : 0;
3745 height = lf.lfHeight;
3747 face = best = best_bitmap = NULL;
3748 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3750 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3752 BOOL italic, bold;
3754 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3755 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3756 new_score = (italic ^ it) + (bold ^ bd);
3757 if(!best || new_score <= score)
3759 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3760 italic, bold, it, bd);
3761 score = new_score;
3762 best = face;
3763 if(best->scalable && score == 0) break;
3764 if(!best->scalable)
3766 if(height > 0)
3767 newdiff = height - (signed int)(best->size.height);
3768 else
3769 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3770 if(!best_bitmap || new_score < score ||
3771 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3773 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3774 diff = newdiff;
3775 best_bitmap = best;
3776 if(score == 0 && diff == 0) break;
3782 if(best)
3783 face = best->scalable ? best : best_bitmap;
3784 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3785 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3787 ret->fs = face->fs;
3789 if(csi.fs.fsCsb[0]) {
3790 ret->charset = lf.lfCharSet;
3791 ret->codepage = csi.ciACP;
3793 else
3794 ret->charset = get_nearest_charset(face, &ret->codepage);
3796 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3797 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3799 ret->aveWidth = height ? lf.lfWidth : 0;
3801 if(!face->scalable) {
3802 /* Windows uses integer scaling factors for bitmap fonts */
3803 INT scale, scaled_height;
3805 /* FIXME: rotation of bitmap fonts is ignored */
3806 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3807 if (ret->aveWidth)
3808 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3809 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3811 if (height != 0) height = diff;
3812 height += face->size.height;
3814 scale = (height + face->size.height - 1) / face->size.height;
3815 scaled_height = scale * face->size.height;
3816 /* Only jump to the next height if the difference <= 25% original height */
3817 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3818 /* The jump between unscaled and doubled is delayed by 1 */
3819 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3820 ret->scale_y = scale;
3822 width = face->size.x_ppem >> 6;
3823 height = face->size.y_ppem >> 6;
3825 else
3826 ret->scale_y = 1.0;
3827 TRACE("font scale y: %f\n", ret->scale_y);
3829 ret->ft_face = OpenFontFace(ret, face, width, height);
3831 if (!ret->ft_face)
3833 free_font( ret );
3834 LeaveCriticalSection( &freetype_cs );
3835 return 0;
3838 ret->ntmFlags = face->ntmFlags;
3840 if (ret->charset == SYMBOL_CHARSET &&
3841 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3842 /* No ops */
3844 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3845 /* No ops */
3847 else {
3848 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3851 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3852 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3853 ret->underline = lf.lfUnderline ? 0xff : 0;
3854 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3855 create_child_font_list(ret);
3857 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3859 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3860 if (length != GDI_ERROR)
3862 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3863 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3864 TRACE("Loaded GSUB table of %i bytes\n",length);
3868 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3870 add_to_cache(ret);
3871 LeaveCriticalSection( &freetype_cs );
3872 return ret;
3875 static void dump_gdi_font_list(void)
3877 GdiFont *gdiFont;
3878 struct list *elem_ptr;
3880 TRACE("---------- gdiFont Cache ----------\n");
3881 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3882 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3883 TRACE("gdiFont=%p %s %d\n",
3884 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3887 TRACE("---------- Unused gdiFont Cache ----------\n");
3888 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3889 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3890 TRACE("gdiFont=%p %s %d\n",
3891 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3895 /*************************************************************
3896 * WineEngDestroyFontInstance
3898 * free the gdiFont associated with this handle
3901 BOOL WineEngDestroyFontInstance(HFONT handle)
3903 GdiFont *gdiFont;
3904 HFONTLIST *hflist;
3905 BOOL ret = FALSE;
3906 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3907 int i = 0;
3909 GDI_CheckNotLock();
3910 EnterCriticalSection( &freetype_cs );
3912 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3914 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3915 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3916 if(hflist->hfont == handle)
3918 TRACE("removing child font %p from child list\n", gdiFont);
3919 list_remove(&gdiFont->entry);
3920 LeaveCriticalSection( &freetype_cs );
3921 return TRUE;
3925 TRACE("destroying hfont=%p\n", handle);
3926 if(TRACE_ON(font))
3927 dump_gdi_font_list();
3929 font_elem_ptr = list_head(&gdi_font_list);
3930 while(font_elem_ptr) {
3931 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3932 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3934 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3935 while(hfontlist_elem_ptr) {
3936 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3937 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3938 if(hflist->hfont == handle) {
3939 list_remove(&hflist->entry);
3940 HeapFree(GetProcessHeap(), 0, hflist);
3941 ret = TRUE;
3944 if(list_empty(&gdiFont->hfontlist)) {
3945 TRACE("Moving to Unused list\n");
3946 list_remove(&gdiFont->entry);
3947 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3952 font_elem_ptr = list_head(&unused_gdi_font_list);
3953 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3954 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3955 while(font_elem_ptr) {
3956 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3957 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3958 TRACE("freeing %p\n", gdiFont);
3959 list_remove(&gdiFont->entry);
3960 free_font(gdiFont);
3962 LeaveCriticalSection( &freetype_cs );
3963 return ret;
3966 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3967 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3969 GdiFont *font;
3970 LONG width, height;
3972 if (face->cached_enum_data)
3974 TRACE("Cached\n");
3975 *pelf = face->cached_enum_data->elf;
3976 *pntm = face->cached_enum_data->ntm;
3977 *ptype = face->cached_enum_data->type;
3978 return;
3981 font = alloc_font();
3983 if(face->scalable) {
3984 height = -2048; /* 2048 is the most common em size */
3985 width = 0;
3986 } else {
3987 height = face->size.y_ppem >> 6;
3988 width = face->size.x_ppem >> 6;
3990 font->scale_y = 1.0;
3992 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3994 free_font(font);
3995 return;
3998 font->name = strdupW(face->family->FamilyName);
3999 font->ntmFlags = face->ntmFlags;
4001 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4003 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4005 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4007 lstrcpynW(pelf->elfLogFont.lfFaceName,
4008 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4009 LF_FACESIZE);
4010 lstrcpynW(pelf->elfFullName,
4011 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4012 LF_FULLFACESIZE);
4013 lstrcpynW(pelf->elfStyle,
4014 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4015 LF_FACESIZE);
4017 else
4019 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4021 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4023 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4024 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4025 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4028 pntm->ntmTm.ntmFlags = face->ntmFlags;
4029 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4030 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4031 pntm->ntmFontSig = face->fs;
4033 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4035 pelf->elfLogFont.lfEscapement = 0;
4036 pelf->elfLogFont.lfOrientation = 0;
4037 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4038 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4039 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4040 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4041 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4042 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4043 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4044 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4045 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4046 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4047 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4049 *ptype = 0;
4050 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4051 *ptype |= TRUETYPE_FONTTYPE;
4052 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4053 *ptype |= DEVICE_FONTTYPE;
4054 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4055 *ptype |= RASTER_FONTTYPE;
4057 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4058 if (face->cached_enum_data)
4060 face->cached_enum_data->elf = *pelf;
4061 face->cached_enum_data->ntm = *pntm;
4062 face->cached_enum_data->type = *ptype;
4065 free_font(font);
4068 /*************************************************************
4069 * WineEngEnumFonts
4072 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4074 Family *family;
4075 Face *face;
4076 struct list *family_elem_ptr, *face_elem_ptr;
4077 ENUMLOGFONTEXW elf;
4078 NEWTEXTMETRICEXW ntm;
4079 DWORD type;
4080 FONTSIGNATURE fs;
4081 CHARSETINFO csi;
4082 LOGFONTW lf;
4083 int i;
4085 if (!plf)
4087 lf.lfCharSet = DEFAULT_CHARSET;
4088 lf.lfPitchAndFamily = 0;
4089 lf.lfFaceName[0] = 0;
4090 plf = &lf;
4093 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4095 GDI_CheckNotLock();
4096 EnterCriticalSection( &freetype_cs );
4097 if(plf->lfFaceName[0]) {
4098 FontSubst *psub;
4099 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4101 if(psub) {
4102 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4103 debugstr_w(psub->to.name));
4104 lf = *plf;
4105 strcpyW(lf.lfFaceName, psub->to.name);
4106 plf = &lf;
4109 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4110 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4111 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
4112 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4113 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4114 GetEnumStructs(face, &elf, &ntm, &type);
4115 for(i = 0; i < 32; i++) {
4116 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4117 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4118 strcpyW(elf.elfScript, OEM_DOSW);
4119 i = 32; /* break out of loop */
4120 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4121 continue;
4122 else {
4123 fs.fsCsb[0] = 1L << i;
4124 fs.fsCsb[1] = 0;
4125 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4126 TCI_SRCFONTSIG))
4127 csi.ciCharset = DEFAULT_CHARSET;
4128 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4129 if(csi.ciCharset != DEFAULT_CHARSET) {
4130 elf.elfLogFont.lfCharSet =
4131 ntm.ntmTm.tmCharSet = csi.ciCharset;
4132 if(ElfScriptsW[i])
4133 strcpyW(elf.elfScript, ElfScriptsW[i]);
4134 else
4135 FIXME("Unknown elfscript for bit %d\n", i);
4138 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4139 debugstr_w(elf.elfLogFont.lfFaceName),
4140 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4141 csi.ciCharset, type, debugstr_w(elf.elfScript),
4142 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4143 ntm.ntmTm.ntmFlags);
4144 /* release section before callback (FIXME) */
4145 LeaveCriticalSection( &freetype_cs );
4146 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4147 EnterCriticalSection( &freetype_cs );
4152 } else {
4153 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4154 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4155 face_elem_ptr = list_head(&family->faces);
4156 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4157 GetEnumStructs(face, &elf, &ntm, &type);
4158 for(i = 0; i < 32; i++) {
4159 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4160 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4161 strcpyW(elf.elfScript, OEM_DOSW);
4162 i = 32; /* break out of loop */
4163 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4164 continue;
4165 else {
4166 fs.fsCsb[0] = 1L << i;
4167 fs.fsCsb[1] = 0;
4168 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4169 TCI_SRCFONTSIG))
4170 csi.ciCharset = DEFAULT_CHARSET;
4171 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4172 if(csi.ciCharset != DEFAULT_CHARSET) {
4173 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4174 csi.ciCharset;
4175 if(ElfScriptsW[i])
4176 strcpyW(elf.elfScript, ElfScriptsW[i]);
4177 else
4178 FIXME("Unknown elfscript for bit %d\n", i);
4181 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4182 debugstr_w(elf.elfLogFont.lfFaceName),
4183 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4184 csi.ciCharset, type, debugstr_w(elf.elfScript),
4185 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4186 ntm.ntmTm.ntmFlags);
4187 /* release section before callback (FIXME) */
4188 LeaveCriticalSection( &freetype_cs );
4189 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4190 EnterCriticalSection( &freetype_cs );
4194 LeaveCriticalSection( &freetype_cs );
4195 return 1;
4198 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4200 pt->x.value = vec->x >> 6;
4201 pt->x.fract = (vec->x & 0x3f) << 10;
4202 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4203 pt->y.value = vec->y >> 6;
4204 pt->y.fract = (vec->y & 0x3f) << 10;
4205 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4206 return;
4209 /***************************************************
4210 * According to the MSDN documentation on WideCharToMultiByte,
4211 * certain codepages cannot set the default_used parameter.
4212 * This returns TRUE if the codepage can set that parameter, false else
4213 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4215 static BOOL codepage_sets_default_used(UINT codepage)
4217 switch (codepage)
4219 case CP_UTF7:
4220 case CP_UTF8:
4221 case CP_SYMBOL:
4222 return FALSE;
4223 default:
4224 return TRUE;
4229 * GSUB Table handling functions
4232 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4234 const GSUB_CoverageFormat1* cf1;
4236 cf1 = table;
4238 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4240 int count = GET_BE_WORD(cf1->GlyphCount);
4241 int i;
4242 TRACE("Coverage Format 1, %i glyphs\n",count);
4243 for (i = 0; i < count; i++)
4244 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4245 return i;
4246 return -1;
4248 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4250 const GSUB_CoverageFormat2* cf2;
4251 int i;
4252 int count;
4253 cf2 = (GSUB_CoverageFormat2*)cf1;
4255 count = GET_BE_WORD(cf2->RangeCount);
4256 TRACE("Coverage Format 2, %i ranges\n",count);
4257 for (i = 0; i < count; i++)
4259 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4260 return -1;
4261 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4262 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4264 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4265 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4268 return -1;
4270 else
4271 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4273 return -1;
4276 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4278 const GSUB_ScriptList *script;
4279 const GSUB_Script *deflt = NULL;
4280 int i;
4281 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4283 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4284 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4286 const GSUB_Script *scr;
4287 int offset;
4289 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4290 scr = (GSUB_Script*)((LPBYTE)script + offset);
4292 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4293 return scr;
4294 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4295 deflt = scr;
4297 return deflt;
4300 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4302 int i;
4303 int offset;
4304 const GSUB_LangSys *Lang;
4306 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4308 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4310 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4311 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4313 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4314 return Lang;
4316 offset = GET_BE_WORD(script->DefaultLangSys);
4317 if (offset)
4319 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4320 return Lang;
4322 return NULL;
4325 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4327 int i;
4328 const GSUB_FeatureList *feature;
4329 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4331 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4332 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4334 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4335 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4337 const GSUB_Feature *feat;
4338 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4339 return feat;
4342 return NULL;
4345 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4347 int i;
4348 int offset;
4349 const GSUB_LookupList *lookup;
4350 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4352 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4353 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4355 const GSUB_LookupTable *look;
4356 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4357 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4358 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4359 if (GET_BE_WORD(look->LookupType) != 1)
4360 FIXME("We only handle SubType 1\n");
4361 else
4363 int j;
4365 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4367 const GSUB_SingleSubstFormat1 *ssf1;
4368 offset = GET_BE_WORD(look->SubTable[j]);
4369 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4370 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4372 int offset = GET_BE_WORD(ssf1->Coverage);
4373 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4374 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4376 TRACE(" Glyph 0x%x ->",glyph);
4377 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4378 TRACE(" 0x%x\n",glyph);
4381 else
4383 const GSUB_SingleSubstFormat2 *ssf2;
4384 INT index;
4385 INT offset;
4387 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4388 offset = GET_BE_WORD(ssf1->Coverage);
4389 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4390 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4391 TRACE(" Coverage index %i\n",index);
4392 if (index != -1)
4394 TRACE(" Glyph is 0x%x ->",glyph);
4395 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4396 TRACE("0x%x\n",glyph);
4402 return glyph;
4405 static const char* get_opentype_script(const GdiFont *font)
4408 * I am not sure if this is the correct way to generate our script tag
4411 switch (font->charset)
4413 case ANSI_CHARSET: return "latn";
4414 case BALTIC_CHARSET: return "latn"; /* ?? */
4415 case CHINESEBIG5_CHARSET: return "hani";
4416 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4417 case GB2312_CHARSET: return "hani";
4418 case GREEK_CHARSET: return "grek";
4419 case HANGUL_CHARSET: return "hang";
4420 case RUSSIAN_CHARSET: return "cyrl";
4421 case SHIFTJIS_CHARSET: return "kana";
4422 case TURKISH_CHARSET: return "latn"; /* ?? */
4423 case VIETNAMESE_CHARSET: return "latn";
4424 case JOHAB_CHARSET: return "latn"; /* ?? */
4425 case ARABIC_CHARSET: return "arab";
4426 case HEBREW_CHARSET: return "hebr";
4427 case THAI_CHARSET: return "thai";
4428 default: return "latn";
4432 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4434 const GSUB_Header *header;
4435 const GSUB_Script *script;
4436 const GSUB_LangSys *language;
4437 const GSUB_Feature *feature;
4439 if (!font->GSUB_Table)
4440 return glyph;
4442 header = font->GSUB_Table;
4444 script = GSUB_get_script_table(header, get_opentype_script(font));
4445 if (!script)
4447 TRACE("Script not found\n");
4448 return glyph;
4450 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4451 if (!language)
4453 TRACE("Language not found\n");
4454 return glyph;
4456 feature = GSUB_get_feature(header, language, "vrt2");
4457 if (!feature)
4458 feature = GSUB_get_feature(header, language, "vert");
4459 if (!feature)
4461 TRACE("vrt2/vert feature not found\n");
4462 return glyph;
4464 return GSUB_apply_feature(header, feature, glyph);
4467 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4469 FT_UInt glyphId;
4471 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4472 WCHAR wc = (WCHAR)glyph;
4473 BOOL default_used;
4474 BOOL *default_used_pointer;
4475 FT_UInt ret;
4476 char buf;
4477 default_used_pointer = NULL;
4478 default_used = FALSE;
4479 if (codepage_sets_default_used(font->codepage))
4480 default_used_pointer = &default_used;
4481 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4482 ret = 0;
4483 else
4484 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4485 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4486 return get_GSUB_vert_glyph(font,ret);
4489 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4490 glyph = glyph + 0xf000;
4491 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4492 return get_GSUB_vert_glyph(font,glyphId);
4495 /*************************************************************
4496 * WineEngGetGlyphIndices
4499 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4500 LPWORD pgi, DWORD flags)
4502 int i;
4503 int default_char = -1;
4505 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4507 for(i = 0; i < count; i++)
4509 pgi[i] = get_glyph_index(font, lpstr[i]);
4510 if (pgi[i] == 0)
4512 if (default_char == -1)
4514 if (FT_IS_SFNT(font->ft_face))
4516 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4517 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4519 else
4521 TEXTMETRICW textm;
4522 WineEngGetTextMetrics(font, &textm);
4523 default_char = textm.tmDefaultChar;
4526 pgi[i] = default_char;
4529 return count;
4532 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4534 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4535 return !memcmp(matrix, &identity, sizeof(FMAT2));
4538 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4540 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4541 return !memcmp(matrix, &identity, sizeof(MAT2));
4544 /*************************************************************
4545 * WineEngGetGlyphOutline
4547 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4548 * except that the first parameter is the HWINEENGFONT of the font in
4549 * question rather than an HDC.
4552 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4553 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4554 const MAT2* lpmat)
4556 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4557 FT_Face ft_face = incoming_font->ft_face;
4558 GdiFont *font = incoming_font;
4559 FT_UInt glyph_index;
4560 DWORD width, height, pitch, needed = 0;
4561 FT_Bitmap ft_bitmap;
4562 FT_Error err;
4563 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4564 FT_Angle angle = 0;
4565 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4566 double widthRatio = 1.0;
4567 FT_Matrix transMat = identityMat;
4568 FT_Matrix transMatUnrotated;
4569 BOOL needsTransform = FALSE;
4570 BOOL tategaki = (font->GSUB_Table != NULL);
4571 UINT original_index;
4573 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4574 buflen, buf, lpmat);
4576 TRACE("font transform %f %f %f %f\n",
4577 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4578 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4580 GDI_CheckNotLock();
4581 EnterCriticalSection( &freetype_cs );
4583 if(format & GGO_GLYPH_INDEX) {
4584 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4585 original_index = glyph;
4586 format &= ~GGO_GLYPH_INDEX;
4587 } else {
4588 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4589 ft_face = font->ft_face;
4590 original_index = glyph_index;
4593 if(format & GGO_UNHINTED) {
4594 load_flags |= FT_LOAD_NO_HINTING;
4595 format &= ~GGO_UNHINTED;
4598 /* tategaki never appears to happen to lower glyph index */
4599 if (glyph_index < TATEGAKI_LOWER_BOUND )
4600 tategaki = FALSE;
4602 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4603 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4604 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4605 font->gmsize * sizeof(GM*));
4606 } else {
4607 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4608 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4610 *lpgm = FONT_GM(font,original_index)->gm;
4611 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4612 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4613 lpgm->gmCellIncX, lpgm->gmCellIncY);
4614 LeaveCriticalSection( &freetype_cs );
4615 return 1; /* FIXME */
4619 if (!font->gm[original_index / GM_BLOCK_SIZE])
4620 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4622 /* Scaling factor */
4623 if (font->aveWidth)
4625 TEXTMETRICW tm;
4627 WineEngGetTextMetrics(font, &tm);
4629 widthRatio = (double)font->aveWidth;
4630 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4632 else
4633 widthRatio = font->scale_y;
4635 /* Scaling transform */
4636 if (widthRatio != 1.0 || font->scale_y != 1.0)
4638 FT_Matrix scaleMat;
4639 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4640 scaleMat.xy = 0;
4641 scaleMat.yx = 0;
4642 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4644 pFT_Matrix_Multiply(&scaleMat, &transMat);
4645 needsTransform = TRUE;
4648 /* Slant transform */
4649 if (font->fake_italic) {
4650 FT_Matrix slantMat;
4652 slantMat.xx = (1 << 16);
4653 slantMat.xy = ((1 << 16) >> 2);
4654 slantMat.yx = 0;
4655 slantMat.yy = (1 << 16);
4656 pFT_Matrix_Multiply(&slantMat, &transMat);
4657 needsTransform = TRUE;
4660 /* Rotation transform */
4661 transMatUnrotated = transMat;
4662 if(font->orientation && !tategaki) {
4663 FT_Matrix rotationMat;
4664 FT_Vector vecAngle;
4665 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4666 pFT_Vector_Unit(&vecAngle, angle);
4667 rotationMat.xx = vecAngle.x;
4668 rotationMat.xy = -vecAngle.y;
4669 rotationMat.yx = -rotationMat.xy;
4670 rotationMat.yy = rotationMat.xx;
4672 pFT_Matrix_Multiply(&rotationMat, &transMat);
4673 needsTransform = TRUE;
4676 /* World transform */
4677 if (!is_identity_FMAT2(&font->font_desc.matrix))
4679 FT_Matrix worldMat;
4680 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4681 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4682 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4683 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4684 pFT_Matrix_Multiply(&worldMat, &transMat);
4685 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4686 needsTransform = TRUE;
4689 /* Extra transformation specified by caller */
4690 if (!is_identity_MAT2(lpmat))
4692 FT_Matrix extraMat;
4693 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4694 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4695 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4696 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4697 pFT_Matrix_Multiply(&extraMat, &transMat);
4698 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4699 needsTransform = TRUE;
4702 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4703 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4704 format == GGO_GRAY8_BITMAP))
4706 load_flags |= FT_LOAD_NO_BITMAP;
4709 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4711 if(err) {
4712 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4713 LeaveCriticalSection( &freetype_cs );
4714 return GDI_ERROR;
4717 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4718 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4720 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4721 lsb = left >> 6;
4722 bbx = (right - left) >> 6;
4724 if(!needsTransform) {
4725 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4726 bottom = (ft_face->glyph->metrics.horiBearingY -
4727 ft_face->glyph->metrics.height) & -64;
4728 lpgm->gmCellIncX = adv;
4729 lpgm->gmCellIncY = 0;
4730 } else {
4731 INT xc, yc;
4732 FT_Vector vec;
4733 for(xc = 0; xc < 2; xc++) {
4734 for(yc = 0; yc < 2; yc++) {
4735 vec.x = (ft_face->glyph->metrics.horiBearingX +
4736 xc * ft_face->glyph->metrics.width);
4737 vec.y = ft_face->glyph->metrics.horiBearingY -
4738 yc * ft_face->glyph->metrics.height;
4739 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4740 pFT_Vector_Transform(&vec, &transMat);
4741 if(xc == 0 && yc == 0) {
4742 left = right = vec.x;
4743 top = bottom = vec.y;
4744 } else {
4745 if(vec.x < left) left = vec.x;
4746 else if(vec.x > right) right = vec.x;
4747 if(vec.y < bottom) bottom = vec.y;
4748 else if(vec.y > top) top = vec.y;
4752 left = left & -64;
4753 right = (right + 63) & -64;
4754 bottom = bottom & -64;
4755 top = (top + 63) & -64;
4757 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4758 vec.x = ft_face->glyph->metrics.horiAdvance;
4759 vec.y = 0;
4760 pFT_Vector_Transform(&vec, &transMat);
4761 lpgm->gmCellIncX = (vec.x+63) >> 6;
4762 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4764 vec.x = ft_face->glyph->metrics.horiAdvance;
4765 vec.y = 0;
4766 pFT_Vector_Transform(&vec, &transMatUnrotated);
4767 adv = (vec.x+63) >> 6;
4769 lpgm->gmBlackBoxX = (right - left) >> 6;
4770 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4771 lpgm->gmptGlyphOrigin.x = left >> 6;
4772 lpgm->gmptGlyphOrigin.y = top >> 6;
4774 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4775 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4776 lpgm->gmCellIncX, lpgm->gmCellIncY);
4778 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4779 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4781 FONT_GM(font,original_index)->gm = *lpgm;
4782 FONT_GM(font,original_index)->adv = adv;
4783 FONT_GM(font,original_index)->lsb = lsb;
4784 FONT_GM(font,original_index)->bbx = bbx;
4785 FONT_GM(font,original_index)->init = TRUE;
4788 if(format == GGO_METRICS)
4790 LeaveCriticalSection( &freetype_cs );
4791 return 1; /* FIXME */
4794 if(ft_face->glyph->format != ft_glyph_format_outline &&
4795 (format == GGO_NATIVE || format == GGO_BEZIER ||
4796 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4797 format == GGO_GRAY8_BITMAP))
4799 TRACE("loaded a bitmap\n");
4800 LeaveCriticalSection( &freetype_cs );
4801 return GDI_ERROR;
4804 switch(format) {
4805 case GGO_BITMAP:
4806 width = lpgm->gmBlackBoxX;
4807 height = lpgm->gmBlackBoxY;
4808 pitch = ((width + 31) >> 5) << 2;
4809 needed = pitch * height;
4811 if(!buf || !buflen) break;
4813 switch(ft_face->glyph->format) {
4814 case ft_glyph_format_bitmap:
4816 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4817 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4818 INT h = ft_face->glyph->bitmap.rows;
4819 while(h--) {
4820 memcpy(dst, src, w);
4821 src += ft_face->glyph->bitmap.pitch;
4822 dst += pitch;
4824 break;
4827 case ft_glyph_format_outline:
4828 ft_bitmap.width = width;
4829 ft_bitmap.rows = height;
4830 ft_bitmap.pitch = pitch;
4831 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4832 ft_bitmap.buffer = buf;
4834 if(needsTransform)
4835 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4837 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4839 /* Note: FreeType will only set 'black' bits for us. */
4840 memset(buf, 0, needed);
4841 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4842 break;
4844 default:
4845 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4846 LeaveCriticalSection( &freetype_cs );
4847 return GDI_ERROR;
4849 break;
4851 case GGO_GRAY2_BITMAP:
4852 case GGO_GRAY4_BITMAP:
4853 case GGO_GRAY8_BITMAP:
4854 case WINE_GGO_GRAY16_BITMAP:
4856 unsigned int mult, row, col;
4857 BYTE *start, *ptr;
4859 width = lpgm->gmBlackBoxX;
4860 height = lpgm->gmBlackBoxY;
4861 pitch = (width + 3) / 4 * 4;
4862 needed = pitch * height;
4864 if(!buf || !buflen) break;
4866 switch(ft_face->glyph->format) {
4867 case ft_glyph_format_bitmap:
4869 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4870 INT h = ft_face->glyph->bitmap.rows;
4871 INT x;
4872 while(h--) {
4873 for(x = 0; x < pitch; x++)
4875 if(x < ft_face->glyph->bitmap.width)
4876 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4877 else
4878 dst[x] = 0;
4880 src += ft_face->glyph->bitmap.pitch;
4881 dst += pitch;
4883 LeaveCriticalSection( &freetype_cs );
4884 return needed;
4886 case ft_glyph_format_outline:
4888 ft_bitmap.width = width;
4889 ft_bitmap.rows = height;
4890 ft_bitmap.pitch = pitch;
4891 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4892 ft_bitmap.buffer = buf;
4894 if(needsTransform)
4895 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4897 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4899 memset(ft_bitmap.buffer, 0, buflen);
4901 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4903 if(format == GGO_GRAY2_BITMAP)
4904 mult = 4;
4905 else if(format == GGO_GRAY4_BITMAP)
4906 mult = 16;
4907 else if(format == GGO_GRAY8_BITMAP)
4908 mult = 64;
4909 else /* format == WINE_GGO_GRAY16_BITMAP */
4911 LeaveCriticalSection( &freetype_cs );
4912 return needed;
4914 break;
4916 default:
4917 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4918 LeaveCriticalSection( &freetype_cs );
4919 return GDI_ERROR;
4922 start = buf;
4923 for(row = 0; row < height; row++) {
4924 ptr = start;
4925 for(col = 0; col < width; col++, ptr++) {
4926 *ptr = (((int)*ptr) * mult + 128) / 256;
4928 start += pitch;
4930 break;
4933 case WINE_GGO_HRGB_BITMAP:
4934 case WINE_GGO_HBGR_BITMAP:
4935 case WINE_GGO_VRGB_BITMAP:
4936 case WINE_GGO_VBGR_BITMAP:
4937 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4939 switch (ft_face->glyph->format)
4941 case FT_GLYPH_FORMAT_BITMAP:
4943 BYTE *src, *dst;
4944 INT src_pitch, x;
4946 width = lpgm->gmBlackBoxX;
4947 height = lpgm->gmBlackBoxY;
4948 pitch = width * 4;
4949 needed = pitch * height;
4951 if (!buf || !buflen) break;
4953 memset(buf, 0, buflen);
4954 dst = buf;
4955 src = ft_face->glyph->bitmap.buffer;
4956 src_pitch = ft_face->glyph->bitmap.pitch;
4958 while ( height-- )
4960 for (x = 0; x < width; x++)
4962 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4963 ((unsigned int *)dst)[x] = ~0u;
4965 src += src_pitch;
4966 dst += pitch;
4969 break;
4972 case FT_GLYPH_FORMAT_OUTLINE:
4974 unsigned int *dst;
4975 BYTE *src;
4976 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4977 INT x_shift, y_shift;
4978 BOOL rgb;
4979 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4980 FT_Render_Mode render_mode =
4981 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4982 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4984 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4986 if ( render_mode == FT_RENDER_MODE_LCD)
4988 lpgm->gmBlackBoxX += 2;
4989 lpgm->gmptGlyphOrigin.x -= 1;
4991 else
4993 lpgm->gmBlackBoxY += 2;
4994 lpgm->gmptGlyphOrigin.y += 1;
4998 width = lpgm->gmBlackBoxX;
4999 height = lpgm->gmBlackBoxY;
5000 pitch = width * 4;
5001 needed = pitch * height;
5003 if (!buf || !buflen) break;
5005 memset(buf, 0, buflen);
5006 dst = buf;
5007 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5009 if ( needsTransform )
5010 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5012 if ( pFT_Library_SetLcdFilter )
5013 pFT_Library_SetLcdFilter( library, lcdfilter );
5014 pFT_Render_Glyph (ft_face->glyph, render_mode);
5016 src = ft_face->glyph->bitmap.buffer;
5017 src_pitch = ft_face->glyph->bitmap.pitch;
5018 src_width = ft_face->glyph->bitmap.width;
5019 src_height = ft_face->glyph->bitmap.rows;
5021 if ( render_mode == FT_RENDER_MODE_LCD)
5023 rgb_interval = 1;
5024 hmul = 3;
5025 vmul = 1;
5027 else
5029 rgb_interval = src_pitch;
5030 hmul = 1;
5031 vmul = 3;
5034 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5035 if ( x_shift < 0 ) x_shift = 0;
5036 if ( x_shift + (src_width / hmul) > width )
5037 x_shift = width - (src_width / hmul);
5039 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5040 if ( y_shift < 0 ) y_shift = 0;
5041 if ( y_shift + (src_height / vmul) > height )
5042 y_shift = height - (src_height / vmul);
5044 dst += x_shift + y_shift * ( pitch / 4 );
5045 while ( src_height )
5047 for ( x = 0; x < src_width / hmul; x++ )
5049 if ( rgb )
5051 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5052 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5053 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5054 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5056 else
5058 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5059 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5060 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5061 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5064 src += src_pitch * vmul;
5065 dst += pitch / 4;
5066 src_height -= vmul;
5069 break;
5072 default:
5073 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5074 LeaveCriticalSection ( &freetype_cs );
5075 return GDI_ERROR;
5078 break;
5080 #else
5081 LeaveCriticalSection( &freetype_cs );
5082 return GDI_ERROR;
5083 #endif
5085 case GGO_NATIVE:
5087 int contour, point = 0, first_pt;
5088 FT_Outline *outline = &ft_face->glyph->outline;
5089 TTPOLYGONHEADER *pph;
5090 TTPOLYCURVE *ppc;
5091 DWORD pph_start, cpfx, type;
5093 if(buflen == 0) buf = NULL;
5095 if (needsTransform && buf) {
5096 pFT_Outline_Transform(outline, &transMat);
5099 for(contour = 0; contour < outline->n_contours; contour++) {
5100 pph_start = needed;
5101 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5102 first_pt = point;
5103 if(buf) {
5104 pph->dwType = TT_POLYGON_TYPE;
5105 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5107 needed += sizeof(*pph);
5108 point++;
5109 while(point <= outline->contours[contour]) {
5110 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5111 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5112 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5113 cpfx = 0;
5114 do {
5115 if(buf)
5116 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5117 cpfx++;
5118 point++;
5119 } while(point <= outline->contours[contour] &&
5120 (outline->tags[point] & FT_Curve_Tag_On) ==
5121 (outline->tags[point-1] & FT_Curve_Tag_On));
5122 /* At the end of a contour Windows adds the start point, but
5123 only for Beziers */
5124 if(point > outline->contours[contour] &&
5125 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5126 if(buf)
5127 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5128 cpfx++;
5129 } else if(point <= outline->contours[contour] &&
5130 outline->tags[point] & FT_Curve_Tag_On) {
5131 /* add closing pt for bezier */
5132 if(buf)
5133 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5134 cpfx++;
5135 point++;
5137 if(buf) {
5138 ppc->wType = type;
5139 ppc->cpfx = cpfx;
5141 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5143 if(buf)
5144 pph->cb = needed - pph_start;
5146 break;
5148 case GGO_BEZIER:
5150 /* Convert the quadratic Beziers to cubic Beziers.
5151 The parametric eqn for a cubic Bezier is, from PLRM:
5152 r(t) = at^3 + bt^2 + ct + r0
5153 with the control points:
5154 r1 = r0 + c/3
5155 r2 = r1 + (c + b)/3
5156 r3 = r0 + c + b + a
5158 A quadratic Beizer has the form:
5159 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5161 So equating powers of t leads to:
5162 r1 = 2/3 p1 + 1/3 p0
5163 r2 = 2/3 p1 + 1/3 p2
5164 and of course r0 = p0, r3 = p2
5167 int contour, point = 0, first_pt;
5168 FT_Outline *outline = &ft_face->glyph->outline;
5169 TTPOLYGONHEADER *pph;
5170 TTPOLYCURVE *ppc;
5171 DWORD pph_start, cpfx, type;
5172 FT_Vector cubic_control[4];
5173 if(buflen == 0) buf = NULL;
5175 if (needsTransform && buf) {
5176 pFT_Outline_Transform(outline, &transMat);
5179 for(contour = 0; contour < outline->n_contours; contour++) {
5180 pph_start = needed;
5181 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5182 first_pt = point;
5183 if(buf) {
5184 pph->dwType = TT_POLYGON_TYPE;
5185 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5187 needed += sizeof(*pph);
5188 point++;
5189 while(point <= outline->contours[contour]) {
5190 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5191 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5192 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5193 cpfx = 0;
5194 do {
5195 if(type == TT_PRIM_LINE) {
5196 if(buf)
5197 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5198 cpfx++;
5199 point++;
5200 } else {
5201 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5202 so cpfx = 3n */
5204 /* FIXME: Possible optimization in endpoint calculation
5205 if there are two consecutive curves */
5206 cubic_control[0] = outline->points[point-1];
5207 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5208 cubic_control[0].x += outline->points[point].x + 1;
5209 cubic_control[0].y += outline->points[point].y + 1;
5210 cubic_control[0].x >>= 1;
5211 cubic_control[0].y >>= 1;
5213 if(point+1 > outline->contours[contour])
5214 cubic_control[3] = outline->points[first_pt];
5215 else {
5216 cubic_control[3] = outline->points[point+1];
5217 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5218 cubic_control[3].x += outline->points[point].x + 1;
5219 cubic_control[3].y += outline->points[point].y + 1;
5220 cubic_control[3].x >>= 1;
5221 cubic_control[3].y >>= 1;
5224 /* r1 = 1/3 p0 + 2/3 p1
5225 r2 = 1/3 p2 + 2/3 p1 */
5226 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5227 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5228 cubic_control[2] = cubic_control[1];
5229 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5230 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5231 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5232 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5233 if(buf) {
5234 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5235 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5236 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5238 cpfx += 3;
5239 point++;
5241 } while(point <= outline->contours[contour] &&
5242 (outline->tags[point] & FT_Curve_Tag_On) ==
5243 (outline->tags[point-1] & FT_Curve_Tag_On));
5244 /* At the end of a contour Windows adds the start point,
5245 but only for Beziers and we've already done that.
5247 if(point <= outline->contours[contour] &&
5248 outline->tags[point] & FT_Curve_Tag_On) {
5249 /* This is the closing pt of a bezier, but we've already
5250 added it, so just inc point and carry on */
5251 point++;
5253 if(buf) {
5254 ppc->wType = type;
5255 ppc->cpfx = cpfx;
5257 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5259 if(buf)
5260 pph->cb = needed - pph_start;
5262 break;
5265 default:
5266 FIXME("Unsupported format %d\n", format);
5267 LeaveCriticalSection( &freetype_cs );
5268 return GDI_ERROR;
5270 LeaveCriticalSection( &freetype_cs );
5271 return needed;
5274 static BOOL get_bitmap_text_metrics(GdiFont *font)
5276 FT_Face ft_face = font->ft_face;
5277 #ifdef HAVE_FREETYPE_FTWINFNT_H
5278 FT_WinFNT_HeaderRec winfnt_header;
5279 #endif
5280 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5281 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5282 font->potm->otmSize = size;
5284 #define TM font->potm->otmTextMetrics
5285 #ifdef HAVE_FREETYPE_FTWINFNT_H
5286 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5288 TM.tmHeight = winfnt_header.pixel_height;
5289 TM.tmAscent = winfnt_header.ascent;
5290 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5291 TM.tmInternalLeading = winfnt_header.internal_leading;
5292 TM.tmExternalLeading = winfnt_header.external_leading;
5293 TM.tmAveCharWidth = winfnt_header.avg_width;
5294 TM.tmMaxCharWidth = winfnt_header.max_width;
5295 TM.tmWeight = winfnt_header.weight;
5296 TM.tmOverhang = 0;
5297 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5298 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5299 TM.tmFirstChar = winfnt_header.first_char;
5300 TM.tmLastChar = winfnt_header.last_char;
5301 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5302 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5303 TM.tmItalic = winfnt_header.italic;
5304 TM.tmUnderlined = font->underline;
5305 TM.tmStruckOut = font->strikeout;
5306 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5307 TM.tmCharSet = winfnt_header.charset;
5309 else
5310 #endif
5312 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5313 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5314 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5315 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5316 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5317 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5318 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5319 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5320 TM.tmOverhang = 0;
5321 TM.tmDigitizedAspectX = 96; /* FIXME */
5322 TM.tmDigitizedAspectY = 96; /* FIXME */
5323 TM.tmFirstChar = 1;
5324 TM.tmLastChar = 255;
5325 TM.tmDefaultChar = 32;
5326 TM.tmBreakChar = 32;
5327 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5328 TM.tmUnderlined = font->underline;
5329 TM.tmStruckOut = font->strikeout;
5330 /* NB inverted meaning of TMPF_FIXED_PITCH */
5331 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5332 TM.tmCharSet = font->charset;
5334 #undef TM
5336 return TRUE;
5340 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5342 double scale_x, scale_y;
5344 if (font->aveWidth)
5346 scale_x = (double)font->aveWidth;
5347 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5349 else
5350 scale_x = font->scale_y;
5352 scale_x *= fabs(font->font_desc.matrix.eM11);
5353 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5355 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5356 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5358 SCALE_Y(ptm->tmHeight);
5359 SCALE_Y(ptm->tmAscent);
5360 SCALE_Y(ptm->tmDescent);
5361 SCALE_Y(ptm->tmInternalLeading);
5362 SCALE_Y(ptm->tmExternalLeading);
5363 SCALE_Y(ptm->tmOverhang);
5365 SCALE_X(ptm->tmAveCharWidth);
5366 SCALE_X(ptm->tmMaxCharWidth);
5368 #undef SCALE_X
5369 #undef SCALE_Y
5372 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5374 double scale_x, scale_y;
5376 if (font->aveWidth)
5378 scale_x = (double)font->aveWidth;
5379 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5381 else
5382 scale_x = font->scale_y;
5384 scale_x *= fabs(font->font_desc.matrix.eM11);
5385 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5387 scale_font_metrics(font, &potm->otmTextMetrics);
5389 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5390 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5392 SCALE_Y(potm->otmAscent);
5393 SCALE_Y(potm->otmDescent);
5394 SCALE_Y(potm->otmLineGap);
5395 SCALE_Y(potm->otmsCapEmHeight);
5396 SCALE_Y(potm->otmsXHeight);
5397 SCALE_Y(potm->otmrcFontBox.top);
5398 SCALE_Y(potm->otmrcFontBox.bottom);
5399 SCALE_X(potm->otmrcFontBox.left);
5400 SCALE_X(potm->otmrcFontBox.right);
5401 SCALE_Y(potm->otmMacAscent);
5402 SCALE_Y(potm->otmMacDescent);
5403 SCALE_Y(potm->otmMacLineGap);
5404 SCALE_X(potm->otmptSubscriptSize.x);
5405 SCALE_Y(potm->otmptSubscriptSize.y);
5406 SCALE_X(potm->otmptSubscriptOffset.x);
5407 SCALE_Y(potm->otmptSubscriptOffset.y);
5408 SCALE_X(potm->otmptSuperscriptSize.x);
5409 SCALE_Y(potm->otmptSuperscriptSize.y);
5410 SCALE_X(potm->otmptSuperscriptOffset.x);
5411 SCALE_Y(potm->otmptSuperscriptOffset.y);
5412 SCALE_Y(potm->otmsStrikeoutSize);
5413 SCALE_Y(potm->otmsStrikeoutPosition);
5414 SCALE_Y(potm->otmsUnderscoreSize);
5415 SCALE_Y(potm->otmsUnderscorePosition);
5417 #undef SCALE_X
5418 #undef SCALE_Y
5421 /*************************************************************
5422 * WineEngGetTextMetrics
5425 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5427 GDI_CheckNotLock();
5428 EnterCriticalSection( &freetype_cs );
5429 if(!font->potm) {
5430 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5431 if(!get_bitmap_text_metrics(font))
5433 LeaveCriticalSection( &freetype_cs );
5434 return FALSE;
5437 if(!font->potm)
5439 LeaveCriticalSection( &freetype_cs );
5440 return FALSE;
5442 *ptm = font->potm->otmTextMetrics;
5443 scale_font_metrics(font, ptm);
5444 LeaveCriticalSection( &freetype_cs );
5445 return TRUE;
5448 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5450 int i;
5452 for(i = 0; i < ft_face->num_charmaps; i++)
5454 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5455 return TRUE;
5457 return FALSE;
5460 /*************************************************************
5461 * WineEngGetOutlineTextMetrics
5464 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5465 OUTLINETEXTMETRICW *potm)
5467 FT_Face ft_face = font->ft_face;
5468 UINT needed, lenfam, lensty, ret;
5469 TT_OS2 *pOS2;
5470 TT_HoriHeader *pHori;
5471 TT_Postscript *pPost;
5472 FT_Fixed x_scale, y_scale;
5473 WCHAR *family_nameW, *style_nameW;
5474 static const WCHAR spaceW[] = {' ', '\0'};
5475 char *cp;
5476 INT ascent, descent;
5478 TRACE("font=%p\n", font);
5480 if(!FT_IS_SCALABLE(ft_face))
5481 return 0;
5483 GDI_CheckNotLock();
5484 EnterCriticalSection( &freetype_cs );
5486 if(font->potm) {
5487 if(cbSize >= font->potm->otmSize)
5489 memcpy(potm, font->potm, font->potm->otmSize);
5490 scale_outline_font_metrics(font, potm);
5492 LeaveCriticalSection( &freetype_cs );
5493 return font->potm->otmSize;
5497 needed = sizeof(*potm);
5499 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5500 family_nameW = strdupW(font->name);
5502 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5503 * sizeof(WCHAR);
5504 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5505 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5506 style_nameW, lensty/sizeof(WCHAR));
5508 /* These names should be read from the TT name table */
5510 /* length of otmpFamilyName */
5511 needed += lenfam;
5513 /* length of otmpFaceName */
5514 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5515 needed += lenfam; /* just the family name */
5516 } else {
5517 needed += lenfam + lensty; /* family + " " + style */
5520 /* length of otmpStyleName */
5521 needed += lensty;
5523 /* length of otmpFullName */
5524 needed += lenfam + lensty;
5527 x_scale = ft_face->size->metrics.x_scale;
5528 y_scale = ft_face->size->metrics.y_scale;
5530 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5531 if(!pOS2) {
5532 FIXME("Can't find OS/2 table - not TT font?\n");
5533 ret = 0;
5534 goto end;
5537 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5538 if(!pHori) {
5539 FIXME("Can't find HHEA table - not TT font?\n");
5540 ret = 0;
5541 goto end;
5544 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5546 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",
5547 pOS2->usWinAscent, pOS2->usWinDescent,
5548 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5549 ft_face->ascender, ft_face->descender, ft_face->height,
5550 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5551 ft_face->bbox.yMax, ft_face->bbox.yMin);
5553 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5554 font->potm->otmSize = needed;
5556 #define TM font->potm->otmTextMetrics
5558 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5559 ascent = pHori->Ascender;
5560 descent = -pHori->Descender;
5561 } else {
5562 ascent = pOS2->usWinAscent;
5563 descent = pOS2->usWinDescent;
5566 if(font->yMax) {
5567 TM.tmAscent = font->yMax;
5568 TM.tmDescent = -font->yMin;
5569 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5570 } else {
5571 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5572 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5573 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5574 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5577 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5579 /* MSDN says:
5580 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5582 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5583 ((ascent + descent) -
5584 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5586 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5587 if (TM.tmAveCharWidth == 0) {
5588 TM.tmAveCharWidth = 1;
5590 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5591 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5592 TM.tmOverhang = 0;
5593 TM.tmDigitizedAspectX = 300;
5594 TM.tmDigitizedAspectY = 300;
5595 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5596 * symbol range to 0 - f0ff
5599 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5601 TM.tmFirstChar = 0;
5602 switch(GetACP())
5604 case 1257: /* Baltic */
5605 TM.tmLastChar = 0xf8fd;
5606 break;
5607 default:
5608 TM.tmLastChar = 0xf0ff;
5610 TM.tmBreakChar = 0x20;
5611 TM.tmDefaultChar = 0x1f;
5613 else
5615 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5616 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5618 if(pOS2->usFirstCharIndex <= 1)
5619 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5620 else if (pOS2->usFirstCharIndex > 0xff)
5621 TM.tmBreakChar = 0x20;
5622 else
5623 TM.tmBreakChar = pOS2->usFirstCharIndex;
5624 TM.tmDefaultChar = TM.tmBreakChar - 1;
5626 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5627 TM.tmUnderlined = font->underline;
5628 TM.tmStruckOut = font->strikeout;
5630 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5631 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5632 (pOS2->version == 0xFFFFU ||
5633 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5634 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5635 else
5636 TM.tmPitchAndFamily = 0;
5638 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5640 case PAN_FAMILY_SCRIPT:
5641 TM.tmPitchAndFamily |= FF_SCRIPT;
5642 break;
5644 case PAN_FAMILY_DECORATIVE:
5645 TM.tmPitchAndFamily |= FF_DECORATIVE;
5646 break;
5648 case PAN_ANY:
5649 case PAN_NO_FIT:
5650 case PAN_FAMILY_TEXT_DISPLAY:
5651 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5652 /* which is clearly not what the panose spec says. */
5653 default:
5654 if(TM.tmPitchAndFamily == 0 || /* fixed */
5655 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5656 TM.tmPitchAndFamily = FF_MODERN;
5657 else
5659 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5661 case PAN_ANY:
5662 case PAN_NO_FIT:
5663 default:
5664 TM.tmPitchAndFamily |= FF_DONTCARE;
5665 break;
5667 case PAN_SERIF_COVE:
5668 case PAN_SERIF_OBTUSE_COVE:
5669 case PAN_SERIF_SQUARE_COVE:
5670 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5671 case PAN_SERIF_SQUARE:
5672 case PAN_SERIF_THIN:
5673 case PAN_SERIF_BONE:
5674 case PAN_SERIF_EXAGGERATED:
5675 case PAN_SERIF_TRIANGLE:
5676 TM.tmPitchAndFamily |= FF_ROMAN;
5677 break;
5679 case PAN_SERIF_NORMAL_SANS:
5680 case PAN_SERIF_OBTUSE_SANS:
5681 case PAN_SERIF_PERP_SANS:
5682 case PAN_SERIF_FLARED:
5683 case PAN_SERIF_ROUNDED:
5684 TM.tmPitchAndFamily |= FF_SWISS;
5685 break;
5688 break;
5691 if(FT_IS_SCALABLE(ft_face))
5692 TM.tmPitchAndFamily |= TMPF_VECTOR;
5694 if(FT_IS_SFNT(ft_face))
5696 if (font->ntmFlags & NTM_PS_OPENTYPE)
5697 TM.tmPitchAndFamily |= TMPF_DEVICE;
5698 else
5699 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5702 TM.tmCharSet = font->charset;
5704 font->potm->otmFiller = 0;
5705 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5706 font->potm->otmfsSelection = pOS2->fsSelection;
5707 font->potm->otmfsType = pOS2->fsType;
5708 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5709 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5710 font->potm->otmItalicAngle = 0; /* POST table */
5711 font->potm->otmEMSquare = ft_face->units_per_EM;
5712 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5713 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5714 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5715 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5716 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5717 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5718 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5719 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5720 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5721 font->potm->otmMacAscent = TM.tmAscent;
5722 font->potm->otmMacDescent = -TM.tmDescent;
5723 font->potm->otmMacLineGap = font->potm->otmLineGap;
5724 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5725 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5726 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5727 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5728 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5729 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5730 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5731 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5732 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5733 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5734 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5735 if(!pPost) {
5736 font->potm->otmsUnderscoreSize = 0;
5737 font->potm->otmsUnderscorePosition = 0;
5738 } else {
5739 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5740 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5742 #undef TM
5744 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5745 cp = (char*)font->potm + sizeof(*font->potm);
5746 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5747 strcpyW((WCHAR*)cp, family_nameW);
5748 cp += lenfam;
5749 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5750 strcpyW((WCHAR*)cp, style_nameW);
5751 cp += lensty;
5752 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5753 strcpyW((WCHAR*)cp, family_nameW);
5754 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5755 strcatW((WCHAR*)cp, spaceW);
5756 strcatW((WCHAR*)cp, style_nameW);
5757 cp += lenfam + lensty;
5758 } else
5759 cp += lenfam;
5760 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5761 strcpyW((WCHAR*)cp, family_nameW);
5762 strcatW((WCHAR*)cp, spaceW);
5763 strcatW((WCHAR*)cp, style_nameW);
5764 ret = needed;
5766 if(potm && needed <= cbSize)
5768 memcpy(potm, font->potm, font->potm->otmSize);
5769 scale_outline_font_metrics(font, potm);
5772 end:
5773 HeapFree(GetProcessHeap(), 0, style_nameW);
5774 HeapFree(GetProcessHeap(), 0, family_nameW);
5776 LeaveCriticalSection( &freetype_cs );
5777 return ret;
5780 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5782 HFONTLIST *hfontlist;
5783 child->font = alloc_font();
5784 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5785 if(!child->font->ft_face)
5787 free_font(child->font);
5788 child->font = NULL;
5789 return FALSE;
5792 child->font->font_desc = font->font_desc;
5793 child->font->ntmFlags = child->face->ntmFlags;
5794 child->font->orientation = font->orientation;
5795 child->font->scale_y = font->scale_y;
5796 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5797 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5798 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5799 child->font->base_font = font;
5800 list_add_head(&child_font_list, &child->font->entry);
5801 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5802 return TRUE;
5805 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5807 FT_UInt g;
5808 CHILD_FONT *child_font;
5810 if(font->base_font)
5811 font = font->base_font;
5813 *linked_font = font;
5815 if((*glyph = get_glyph_index(font, c)))
5816 return TRUE;
5818 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5820 if(!child_font->font)
5821 if(!load_child_font(font, child_font))
5822 continue;
5824 if(!child_font->font->ft_face)
5825 continue;
5826 g = get_glyph_index(child_font->font, c);
5827 if(g)
5829 *glyph = g;
5830 *linked_font = child_font->font;
5831 return TRUE;
5834 return FALSE;
5837 /*************************************************************
5838 * WineEngGetCharWidth
5841 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5842 LPINT buffer)
5844 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5845 UINT c;
5846 GLYPHMETRICS gm;
5847 FT_UInt glyph_index;
5848 GdiFont *linked_font;
5850 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5852 GDI_CheckNotLock();
5853 EnterCriticalSection( &freetype_cs );
5854 for(c = firstChar; c <= lastChar; c++) {
5855 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5856 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5857 &gm, 0, NULL, &identity);
5858 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5860 LeaveCriticalSection( &freetype_cs );
5861 return TRUE;
5864 /*************************************************************
5865 * WineEngGetCharABCWidths
5868 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5869 LPABC buffer)
5871 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5872 UINT c;
5873 GLYPHMETRICS gm;
5874 FT_UInt glyph_index;
5875 GdiFont *linked_font;
5877 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5879 if(!FT_IS_SCALABLE(font->ft_face))
5880 return FALSE;
5882 GDI_CheckNotLock();
5883 EnterCriticalSection( &freetype_cs );
5885 for(c = firstChar; c <= lastChar; c++) {
5886 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5887 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5888 &gm, 0, NULL, &identity);
5889 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5890 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5891 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5892 FONT_GM(linked_font,glyph_index)->bbx;
5894 LeaveCriticalSection( &freetype_cs );
5895 return TRUE;
5898 /*************************************************************
5899 * WineEngGetCharABCWidthsI
5902 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5903 LPABC buffer)
5905 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5906 UINT c;
5907 GLYPHMETRICS gm;
5908 FT_UInt glyph_index;
5909 GdiFont *linked_font;
5911 if(!FT_HAS_HORIZONTAL(font->ft_face))
5912 return FALSE;
5914 GDI_CheckNotLock();
5915 EnterCriticalSection( &freetype_cs );
5917 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5918 if (!pgi)
5919 for(c = firstChar; c < firstChar+count; c++) {
5920 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5921 &gm, 0, NULL, &identity);
5922 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5923 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5924 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5925 - FONT_GM(linked_font,c)->bbx;
5927 else
5928 for(c = 0; c < count; c++) {
5929 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5930 &gm, 0, NULL, &identity);
5931 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5932 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5933 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5934 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5937 LeaveCriticalSection( &freetype_cs );
5938 return TRUE;
5941 /*************************************************************
5942 * WineEngGetTextExtentExPoint
5945 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5946 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5948 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5949 INT idx;
5950 INT nfit = 0, ext;
5951 GLYPHMETRICS gm;
5952 TEXTMETRICW tm;
5953 FT_UInt glyph_index;
5954 GdiFont *linked_font;
5956 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5957 max_ext, size);
5959 GDI_CheckNotLock();
5960 EnterCriticalSection( &freetype_cs );
5962 size->cx = 0;
5963 WineEngGetTextMetrics(font, &tm);
5964 size->cy = tm.tmHeight;
5966 for(idx = 0; idx < count; idx++) {
5967 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5968 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5969 &gm, 0, NULL, &identity);
5970 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5971 ext = size->cx;
5972 if (! pnfit || ext <= max_ext) {
5973 ++nfit;
5974 if (dxs)
5975 dxs[idx] = ext;
5979 if (pnfit)
5980 *pnfit = nfit;
5982 LeaveCriticalSection( &freetype_cs );
5983 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5984 return TRUE;
5987 /*************************************************************
5988 * WineEngGetTextExtentExPointI
5991 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5992 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5994 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5995 INT idx;
5996 INT nfit = 0, ext;
5997 GLYPHMETRICS gm;
5998 TEXTMETRICW tm;
6000 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6002 GDI_CheckNotLock();
6003 EnterCriticalSection( &freetype_cs );
6005 size->cx = 0;
6006 WineEngGetTextMetrics(font, &tm);
6007 size->cy = tm.tmHeight;
6009 for(idx = 0; idx < count; idx++) {
6010 WineEngGetGlyphOutline(font, indices[idx],
6011 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6012 &identity);
6013 size->cx += FONT_GM(font,indices[idx])->adv;
6014 ext = size->cx;
6015 if (! pnfit || ext <= max_ext) {
6016 ++nfit;
6017 if (dxs)
6018 dxs[idx] = ext;
6022 if (pnfit)
6023 *pnfit = nfit;
6025 LeaveCriticalSection( &freetype_cs );
6026 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6027 return TRUE;
6030 /*************************************************************
6031 * WineEngGetFontData
6034 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6035 DWORD cbData)
6037 FT_Face ft_face = font->ft_face;
6038 FT_ULong len;
6039 FT_Error err;
6041 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6042 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6043 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6045 if(!FT_IS_SFNT(ft_face))
6046 return GDI_ERROR;
6048 if(!buf || !cbData)
6049 len = 0;
6050 else
6051 len = cbData;
6053 if(table) { /* MS tags differ in endianness from FT ones */
6054 table = table >> 24 | table << 24 |
6055 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6058 /* make sure value of len is the value freetype says it needs */
6059 if(buf && len)
6061 FT_ULong needed = 0;
6062 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6063 if( !err && needed < len) len = needed;
6065 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6067 if(err) {
6068 TRACE("Can't find table %c%c%c%c\n",
6069 /* bytes were reversed */
6070 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6071 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6072 return GDI_ERROR;
6074 return len;
6077 /*************************************************************
6078 * WineEngGetTextFace
6081 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6083 INT n = strlenW(font->name) + 1;
6084 if(str) {
6085 lstrcpynW(str, font->name, count);
6086 return min(count, n);
6087 } else
6088 return n;
6091 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6093 if (fs) *fs = font->fs;
6094 return font->charset;
6097 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6099 GdiFont *font = dc->gdiFont, *linked_font;
6100 struct list *first_hfont;
6101 BOOL ret;
6103 GDI_CheckNotLock();
6104 EnterCriticalSection( &freetype_cs );
6105 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6106 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6107 if(font == linked_font)
6108 *new_hfont = dc->hFont;
6109 else
6111 first_hfont = list_head(&linked_font->hfontlist);
6112 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6114 LeaveCriticalSection( &freetype_cs );
6115 return ret;
6118 /* Retrieve a list of supported Unicode ranges for a given font.
6119 * Can be called with NULL gs to calculate the buffer size. Returns
6120 * the number of ranges found.
6122 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6124 DWORD num_ranges = 0;
6126 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6128 FT_UInt glyph_code;
6129 FT_ULong char_code, char_code_prev;
6131 glyph_code = 0;
6132 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6134 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6135 face->num_glyphs, glyph_code, char_code);
6137 if (!glyph_code) return 0;
6139 if (gs)
6141 gs->ranges[0].wcLow = (USHORT)char_code;
6142 gs->ranges[0].cGlyphs = 0;
6143 gs->cGlyphsSupported = 0;
6146 num_ranges = 1;
6147 while (glyph_code)
6149 if (char_code < char_code_prev)
6151 ERR("expected increasing char code from FT_Get_Next_Char\n");
6152 return 0;
6154 if (char_code - char_code_prev > 1)
6156 num_ranges++;
6157 if (gs)
6159 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6160 gs->ranges[num_ranges - 1].cGlyphs = 1;
6161 gs->cGlyphsSupported++;
6164 else if (gs)
6166 gs->ranges[num_ranges - 1].cGlyphs++;
6167 gs->cGlyphsSupported++;
6169 char_code_prev = char_code;
6170 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6173 else
6174 FIXME("encoding %u not supported\n", face->charmap->encoding);
6176 return num_ranges;
6179 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6181 DWORD size = 0;
6182 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6184 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6185 if (glyphset)
6187 glyphset->cbThis = size;
6188 glyphset->cRanges = num_ranges;
6190 return size;
6193 /*************************************************************
6194 * FontIsLinked
6196 BOOL WineEngFontIsLinked(GdiFont *font)
6198 BOOL ret;
6199 GDI_CheckNotLock();
6200 EnterCriticalSection( &freetype_cs );
6201 ret = !list_empty(&font->child_fonts);
6202 LeaveCriticalSection( &freetype_cs );
6203 return ret;
6206 static BOOL is_hinting_enabled(void)
6208 /* Use the >= 2.2.0 function if available */
6209 if(pFT_Get_TrueType_Engine_Type)
6211 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6212 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6214 #ifdef FT_DRIVER_HAS_HINTER
6215 else
6217 FT_Module mod;
6219 /* otherwise if we've been compiled with < 2.2.0 headers
6220 use the internal macro */
6221 mod = pFT_Get_Module(library, "truetype");
6222 if(mod && FT_DRIVER_HAS_HINTER(mod))
6223 return TRUE;
6225 #endif
6227 return FALSE;
6230 static BOOL is_subpixel_rendering_enabled( void )
6232 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6233 return pFT_Library_SetLcdFilter &&
6234 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6235 #else
6236 return FALSE;
6237 #endif
6240 /*************************************************************************
6241 * GetRasterizerCaps (GDI32.@)
6243 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6245 static int hinting = -1;
6246 static int subpixel = -1;
6248 if(hinting == -1)
6250 hinting = is_hinting_enabled();
6251 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6254 if ( subpixel == -1 )
6256 subpixel = is_subpixel_rendering_enabled();
6257 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6260 lprs->nSize = sizeof(RASTERIZER_STATUS);
6261 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6262 if ( subpixel )
6263 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6264 lprs->nLanguageID = 0;
6265 return TRUE;
6268 /*************************************************************
6269 * WineEngRealizationInfo
6271 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6273 FIXME("(%p, %p): stub!\n", font, info);
6275 info->flags = 1;
6276 if(FT_IS_SCALABLE(font->ft_face))
6277 info->flags |= 2;
6279 info->cache_num = font->cache_num;
6280 info->unknown2 = -1;
6281 return TRUE;
6284 /*************************************************************************
6285 * Kerning support for TrueType fonts
6287 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6289 struct TT_kern_table
6291 USHORT version;
6292 USHORT nTables;
6295 struct TT_kern_subtable
6297 USHORT version;
6298 USHORT length;
6299 union
6301 USHORT word;
6302 struct
6304 USHORT horizontal : 1;
6305 USHORT minimum : 1;
6306 USHORT cross_stream: 1;
6307 USHORT override : 1;
6308 USHORT reserved1 : 4;
6309 USHORT format : 8;
6310 } bits;
6311 } coverage;
6314 struct TT_format0_kern_subtable
6316 USHORT nPairs;
6317 USHORT searchRange;
6318 USHORT entrySelector;
6319 USHORT rangeShift;
6322 struct TT_kern_pair
6324 USHORT left;
6325 USHORT right;
6326 short value;
6329 static DWORD parse_format0_kern_subtable(GdiFont *font,
6330 const struct TT_format0_kern_subtable *tt_f0_ks,
6331 const USHORT *glyph_to_char,
6332 KERNINGPAIR *kern_pair, DWORD cPairs)
6334 USHORT i, nPairs;
6335 const struct TT_kern_pair *tt_kern_pair;
6337 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6339 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6341 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6342 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6343 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6345 if (!kern_pair || !cPairs)
6346 return nPairs;
6348 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6350 nPairs = min(nPairs, cPairs);
6352 for (i = 0; i < nPairs; i++)
6354 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6355 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6356 /* this algorithm appears to better match what Windows does */
6357 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6358 if (kern_pair->iKernAmount < 0)
6360 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6361 kern_pair->iKernAmount -= font->ppem;
6363 else if (kern_pair->iKernAmount > 0)
6365 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6366 kern_pair->iKernAmount += font->ppem;
6368 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6370 TRACE("left %u right %u value %d\n",
6371 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6373 kern_pair++;
6375 TRACE("copied %u entries\n", nPairs);
6376 return nPairs;
6379 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6381 DWORD length;
6382 void *buf;
6383 const struct TT_kern_table *tt_kern_table;
6384 const struct TT_kern_subtable *tt_kern_subtable;
6385 USHORT i, nTables;
6386 USHORT *glyph_to_char;
6388 GDI_CheckNotLock();
6389 EnterCriticalSection( &freetype_cs );
6390 if (font->total_kern_pairs != (DWORD)-1)
6392 if (cPairs && kern_pair)
6394 cPairs = min(cPairs, font->total_kern_pairs);
6395 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6396 LeaveCriticalSection( &freetype_cs );
6397 return cPairs;
6399 LeaveCriticalSection( &freetype_cs );
6400 return font->total_kern_pairs;
6403 font->total_kern_pairs = 0;
6405 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6407 if (length == GDI_ERROR)
6409 TRACE("no kerning data in the font\n");
6410 LeaveCriticalSection( &freetype_cs );
6411 return 0;
6414 buf = HeapAlloc(GetProcessHeap(), 0, length);
6415 if (!buf)
6417 WARN("Out of memory\n");
6418 LeaveCriticalSection( &freetype_cs );
6419 return 0;
6422 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6424 /* build a glyph index to char code map */
6425 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6426 if (!glyph_to_char)
6428 WARN("Out of memory allocating a glyph index to char code map\n");
6429 HeapFree(GetProcessHeap(), 0, buf);
6430 LeaveCriticalSection( &freetype_cs );
6431 return 0;
6434 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6436 FT_UInt glyph_code;
6437 FT_ULong char_code;
6439 glyph_code = 0;
6440 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6442 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6443 font->ft_face->num_glyphs, glyph_code, char_code);
6445 while (glyph_code)
6447 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6449 /* FIXME: This doesn't match what Windows does: it does some fancy
6450 * things with duplicate glyph index to char code mappings, while
6451 * we just avoid overriding existing entries.
6453 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6454 glyph_to_char[glyph_code] = (USHORT)char_code;
6456 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6459 else
6461 ULONG n;
6463 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6464 for (n = 0; n <= 65535; n++)
6465 glyph_to_char[n] = (USHORT)n;
6468 tt_kern_table = buf;
6469 nTables = GET_BE_WORD(tt_kern_table->nTables);
6470 TRACE("version %u, nTables %u\n",
6471 GET_BE_WORD(tt_kern_table->version), nTables);
6473 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6475 for (i = 0; i < nTables; i++)
6477 struct TT_kern_subtable tt_kern_subtable_copy;
6479 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6480 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6481 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6483 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6484 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6485 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6487 /* According to the TrueType specification this is the only format
6488 * that will be properly interpreted by Windows and OS/2
6490 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6492 DWORD new_chunk, old_total = font->total_kern_pairs;
6494 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6495 glyph_to_char, NULL, 0);
6496 font->total_kern_pairs += new_chunk;
6498 if (!font->kern_pairs)
6499 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6500 font->total_kern_pairs * sizeof(*font->kern_pairs));
6501 else
6502 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6503 font->total_kern_pairs * sizeof(*font->kern_pairs));
6505 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6506 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6508 else
6509 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6511 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6514 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6515 HeapFree(GetProcessHeap(), 0, buf);
6517 if (cPairs && kern_pair)
6519 cPairs = min(cPairs, font->total_kern_pairs);
6520 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6521 LeaveCriticalSection( &freetype_cs );
6522 return cPairs;
6524 LeaveCriticalSection( &freetype_cs );
6525 return font->total_kern_pairs;
6528 #else /* HAVE_FREETYPE */
6530 /*************************************************************************/
6532 BOOL WineEngInit(void)
6534 return FALSE;
6536 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6538 return NULL;
6540 BOOL WineEngDestroyFontInstance(HFONT hfont)
6542 return FALSE;
6545 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6547 return 1;
6550 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6551 LPWORD pgi, DWORD flags)
6553 return GDI_ERROR;
6556 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6557 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6558 const MAT2* lpmat)
6560 ERR("called but we don't have FreeType\n");
6561 return GDI_ERROR;
6564 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6566 ERR("called but we don't have FreeType\n");
6567 return FALSE;
6570 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6571 OUTLINETEXTMETRICW *potm)
6573 ERR("called but we don't have FreeType\n");
6574 return 0;
6577 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6578 LPINT buffer)
6580 ERR("called but we don't have FreeType\n");
6581 return FALSE;
6584 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6585 LPABC buffer)
6587 ERR("called but we don't have FreeType\n");
6588 return FALSE;
6591 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6592 LPABC buffer)
6594 ERR("called but we don't have FreeType\n");
6595 return FALSE;
6598 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6599 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6601 ERR("called but we don't have FreeType\n");
6602 return FALSE;
6605 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6606 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6608 ERR("called but we don't have FreeType\n");
6609 return FALSE;
6612 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6613 DWORD cbData)
6615 ERR("called but we don't have FreeType\n");
6616 return GDI_ERROR;
6619 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6621 ERR("called but we don't have FreeType\n");
6622 return 0;
6625 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6627 FIXME(":stub\n");
6628 return 1;
6631 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6633 FIXME(":stub\n");
6634 return TRUE;
6637 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6639 FIXME(":stub\n");
6640 return NULL;
6643 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6645 FIXME(":stub\n");
6646 return DEFAULT_CHARSET;
6649 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6651 return FALSE;
6654 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6656 FIXME("(%p, %p): stub\n", font, glyphset);
6657 return 0;
6660 BOOL WineEngFontIsLinked(GdiFont *font)
6662 return FALSE;
6665 /*************************************************************************
6666 * GetRasterizerCaps (GDI32.@)
6668 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6670 lprs->nSize = sizeof(RASTERIZER_STATUS);
6671 lprs->wFlags = 0;
6672 lprs->nLanguageID = 0;
6673 return TRUE;
6676 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6678 ERR("called but we don't have FreeType\n");
6679 return 0;
6682 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6684 ERR("called but we don't have FreeType\n");
6685 return FALSE;
6688 #endif /* HAVE_FREETYPE */