user32: Fix bogus "if (!x & y)" code.
[wine/testsucceed.git] / dlls / gdi32 / freetype.c
blob1ca6953178cac2aef9eff82138d4fb37b01a36de
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 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
404 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
405 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
406 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
407 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
408 'E','u','r','o','p','e','a','n','\0'};
409 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
410 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
411 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
412 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
413 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
414 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
415 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
416 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
417 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
418 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
419 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
420 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
422 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
423 WesternW, /*00*/
424 Central_EuropeanW,
425 CyrillicW,
426 GreekW,
427 TurkishW,
428 HebrewW,
429 ArabicW,
430 BalticW,
431 VietnameseW, /*08*/
432 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
433 ThaiW,
434 JapaneseW,
435 CHINESE_GB2312W,
436 HangulW,
437 CHINESE_BIG5W,
438 Hangul_Johab_W,
439 NULL, NULL, /*23*/
440 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
441 SymbolW /*31*/
444 typedef struct {
445 WCHAR *name;
446 INT charset;
447 } NameCs;
449 typedef struct tagFontSubst {
450 struct list entry;
451 NameCs from;
452 NameCs to;
453 } FontSubst;
455 struct font_mapping
457 struct list entry;
458 int refcount;
459 dev_t dev;
460 ino_t ino;
461 void *data;
462 size_t size;
465 static struct list mappings_list = LIST_INIT( mappings_list );
467 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
469 static CRITICAL_SECTION freetype_cs;
470 static CRITICAL_SECTION_DEBUG critsect_debug =
472 0, 0, &freetype_cs,
473 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
474 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
476 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
478 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
480 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
481 static BOOL use_default_fallback = FALSE;
483 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
485 /****************************************
486 * Notes on .fon files
488 * The fonts System, FixedSys and Terminal are special. There are typically multiple
489 * versions installed for different resolutions and codepages. Windows stores which one to use
490 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
491 * Key Meaning
492 * FIXEDFON.FON FixedSys
493 * FONTS.FON System
494 * OEMFONT.FON Terminal
495 * LogPixels Current dpi set by the display control panel applet
496 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
497 * also has a LogPixels value that appears to mirror this)
499 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
500 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
501 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
502 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
503 * so that makes sense.
505 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
506 * to be mapped into the registry on Windows 2000 at least).
507 * I have
508 * woafont=app850.fon
509 * ega80woa.fon=ega80850.fon
510 * ega40woa.fon=ega40850.fon
511 * cga80woa.fon=cga80850.fon
512 * cga40woa.fon=cga40850.fon
515 /* These are all structures needed for the GSUB table */
517 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
518 #define TATEGAKI_LOWER_BOUND 0x02F1
520 typedef struct {
521 DWORD version;
522 WORD ScriptList;
523 WORD FeatureList;
524 WORD LookupList;
525 } GSUB_Header;
527 typedef struct {
528 CHAR ScriptTag[4];
529 WORD Script;
530 } GSUB_ScriptRecord;
532 typedef struct {
533 WORD ScriptCount;
534 GSUB_ScriptRecord ScriptRecord[1];
535 } GSUB_ScriptList;
537 typedef struct {
538 CHAR LangSysTag[4];
539 WORD LangSys;
540 } GSUB_LangSysRecord;
542 typedef struct {
543 WORD DefaultLangSys;
544 WORD LangSysCount;
545 GSUB_LangSysRecord LangSysRecord[1];
546 } GSUB_Script;
548 typedef struct {
549 WORD LookupOrder; /* Reserved */
550 WORD ReqFeatureIndex;
551 WORD FeatureCount;
552 WORD FeatureIndex[1];
553 } GSUB_LangSys;
555 typedef struct {
556 CHAR FeatureTag[4];
557 WORD Feature;
558 } GSUB_FeatureRecord;
560 typedef struct {
561 WORD FeatureCount;
562 GSUB_FeatureRecord FeatureRecord[1];
563 } GSUB_FeatureList;
565 typedef struct {
566 WORD FeatureParams; /* Reserved */
567 WORD LookupCount;
568 WORD LookupListIndex[1];
569 } GSUB_Feature;
571 typedef struct {
572 WORD LookupCount;
573 WORD Lookup[1];
574 } GSUB_LookupList;
576 typedef struct {
577 WORD LookupType;
578 WORD LookupFlag;
579 WORD SubTableCount;
580 WORD SubTable[1];
581 } GSUB_LookupTable;
583 typedef struct {
584 WORD CoverageFormat;
585 WORD GlyphCount;
586 WORD GlyphArray[1];
587 } GSUB_CoverageFormat1;
589 typedef struct {
590 WORD Start;
591 WORD End;
592 WORD StartCoverageIndex;
593 } GSUB_RangeRecord;
595 typedef struct {
596 WORD CoverageFormat;
597 WORD RangeCount;
598 GSUB_RangeRecord RangeRecord[1];
599 } GSUB_CoverageFormat2;
601 typedef struct {
602 WORD SubstFormat; /* = 1 */
603 WORD Coverage;
604 WORD DeltaGlyphID;
605 } GSUB_SingleSubstFormat1;
607 typedef struct {
608 WORD SubstFormat; /* = 2 */
609 WORD Coverage;
610 WORD GlyphCount;
611 WORD Substitute[1];
612 }GSUB_SingleSubstFormat2;
614 #ifdef HAVE_CARBON_CARBON_H
615 static char *find_cache_dir(void)
617 FSRef ref;
618 OSErr err;
619 static char cached_path[MAX_PATH];
620 static const char *wine = "/Wine", *fonts = "/Fonts";
622 if(*cached_path) return cached_path;
624 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
625 if(err != noErr)
627 WARN("can't create cached data folder\n");
628 return NULL;
630 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
631 if(err != noErr)
633 WARN("can't create cached data path\n");
634 *cached_path = '\0';
635 return NULL;
637 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
639 ERR("Could not create full path\n");
640 *cached_path = '\0';
641 return NULL;
643 strcat(cached_path, wine);
645 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
647 WARN("Couldn't mkdir %s\n", cached_path);
648 *cached_path = '\0';
649 return NULL;
651 strcat(cached_path, fonts);
652 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
654 WARN("Couldn't mkdir %s\n", cached_path);
655 *cached_path = '\0';
656 return NULL;
658 return cached_path;
661 /******************************************************************
662 * expand_mac_font
664 * Extracts individual TrueType font files from a Mac suitcase font
665 * and saves them into the user's caches directory (see
666 * find_cache_dir()).
667 * Returns a NULL terminated array of filenames.
669 * We do this because they are apps that try to read ttf files
670 * themselves and they don't like Mac suitcase files.
672 static char **expand_mac_font(const char *path)
674 FSRef ref;
675 SInt16 res_ref;
676 OSStatus s;
677 unsigned int idx;
678 const char *out_dir;
679 const char *filename;
680 int output_len;
681 struct {
682 char **array;
683 unsigned int size, max_size;
684 } ret;
686 TRACE("path %s\n", path);
688 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
689 if(s != noErr)
691 WARN("failed to get ref\n");
692 return NULL;
695 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
696 if(s != noErr)
698 TRACE("no data fork, so trying resource fork\n");
699 res_ref = FSOpenResFile(&ref, fsRdPerm);
700 if(res_ref == -1)
702 TRACE("unable to open resource fork\n");
703 return NULL;
707 ret.size = 0;
708 ret.max_size = 10;
709 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
710 if(!ret.array)
712 CloseResFile(res_ref);
713 return NULL;
716 out_dir = find_cache_dir();
718 filename = strrchr(path, '/');
719 if(!filename) filename = path;
720 else filename++;
722 /* output filename has the form out_dir/filename_%04x.ttf */
723 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
725 UseResFile(res_ref);
726 idx = 1;
727 while(1)
729 FamRec *fam_rec;
730 unsigned short *num_faces_ptr, num_faces, face;
731 AsscEntry *assoc;
732 Handle fond;
733 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
735 fond = Get1IndResource(fond_res, idx);
736 if(!fond) break;
737 TRACE("got fond resource %d\n", idx);
738 HLock(fond);
740 fam_rec = *(FamRec**)fond;
741 num_faces_ptr = (unsigned short *)(fam_rec + 1);
742 num_faces = GET_BE_WORD(*num_faces_ptr);
743 num_faces++;
744 assoc = (AsscEntry*)(num_faces_ptr + 1);
745 TRACE("num faces %04x\n", num_faces);
746 for(face = 0; face < num_faces; face++, assoc++)
748 Handle sfnt;
749 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
750 unsigned short size, font_id;
751 char *output;
753 size = GET_BE_WORD(assoc->fontSize);
754 font_id = GET_BE_WORD(assoc->fontID);
755 if(size != 0)
757 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
758 continue;
761 TRACE("trying to load sfnt id %04x\n", font_id);
762 sfnt = GetResource(sfnt_res, font_id);
763 if(!sfnt)
765 TRACE("can't get sfnt resource %04x\n", font_id);
766 continue;
769 output = HeapAlloc(GetProcessHeap(), 0, output_len);
770 if(output)
772 int fd;
774 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
776 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
777 if(fd != -1 || errno == EEXIST)
779 if(fd != -1)
781 unsigned char *sfnt_data;
783 HLock(sfnt);
784 sfnt_data = *(unsigned char**)sfnt;
785 write(fd, sfnt_data, GetHandleSize(sfnt));
786 HUnlock(sfnt);
787 close(fd);
789 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
791 ret.max_size *= 2;
792 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
794 ret.array[ret.size++] = output;
796 else
798 WARN("unable to create %s\n", output);
799 HeapFree(GetProcessHeap(), 0, output);
802 ReleaseResource(sfnt);
804 HUnlock(fond);
805 ReleaseResource(fond);
806 idx++;
808 CloseResFile(res_ref);
810 return ret.array;
813 #endif /* HAVE_CARBON_CARBON_H */
815 static inline BOOL is_win9x(void)
817 return GetVersion() & 0x80000000;
820 This function builds an FT_Fixed from a double. It fails if the absolute
821 value of the float number is greater than 32768.
823 static inline FT_Fixed FT_FixedFromFloat(double f)
825 return f * 0x10000;
829 This function builds an FT_Fixed from a FIXED. It simply put f.value
830 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
832 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
834 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
838 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
840 Family *family;
841 Face *face;
842 const char *file;
843 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
844 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
846 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
847 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
849 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
851 if(face_name && strcmpiW(face_name, family->FamilyName))
852 continue;
853 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
855 if (!face->file)
856 continue;
857 file = strrchr(face->file, '/');
858 if(!file)
859 file = face->file;
860 else
861 file++;
862 if(!strcasecmp(file, file_nameA))
864 HeapFree(GetProcessHeap(), 0, file_nameA);
865 return face;
869 HeapFree(GetProcessHeap(), 0, file_nameA);
870 return NULL;
873 static Family *find_family_from_name(const WCHAR *name)
875 Family *family;
877 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
879 if(!strcmpiW(family->FamilyName, name))
880 return family;
883 return NULL;
886 static void DumpSubstList(void)
888 FontSubst *psub;
890 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
892 if(psub->from.charset != -1 || psub->to.charset != -1)
893 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
894 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
895 else
896 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
897 debugstr_w(psub->to.name));
899 return;
902 static LPWSTR strdupW(LPCWSTR p)
904 LPWSTR ret;
905 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
907 memcpy(ret, p, len);
908 return ret;
911 static LPSTR strdupA(LPCSTR p)
913 LPSTR ret;
914 DWORD len = (strlen(p) + 1);
915 ret = HeapAlloc(GetProcessHeap(), 0, len);
916 memcpy(ret, p, len);
917 return ret;
920 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
921 INT from_charset)
923 FontSubst *element;
925 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
927 if(!strcmpiW(element->from.name, from_name) &&
928 (element->from.charset == from_charset ||
929 element->from.charset == -1))
930 return element;
933 return NULL;
936 #define ADD_FONT_SUBST_FORCE 1
938 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
940 FontSubst *from_exist, *to_exist;
942 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
944 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
946 list_remove(&from_exist->entry);
947 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
948 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
949 HeapFree(GetProcessHeap(), 0, from_exist);
950 from_exist = NULL;
953 if(!from_exist)
955 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
957 if(to_exist)
959 HeapFree(GetProcessHeap(), 0, subst->to.name);
960 subst->to.name = strdupW(to_exist->to.name);
963 list_add_tail(subst_list, &subst->entry);
965 return TRUE;
968 HeapFree(GetProcessHeap(), 0, subst->from.name);
969 HeapFree(GetProcessHeap(), 0, subst->to.name);
970 HeapFree(GetProcessHeap(), 0, subst);
971 return FALSE;
974 static void split_subst_info(NameCs *nc, LPSTR str)
976 CHAR *p = strrchr(str, ',');
977 DWORD len;
979 nc->charset = -1;
980 if(p && *(p+1)) {
981 nc->charset = strtol(p+1, NULL, 10);
982 *p = '\0';
984 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
985 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
986 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
989 static void LoadSubstList(void)
991 FontSubst *psub;
992 HKEY hkey;
993 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
994 LPSTR value;
995 LPVOID data;
997 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
998 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
999 &hkey) == ERROR_SUCCESS) {
1001 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1002 &valuelen, &datalen, NULL, NULL);
1004 valuelen++; /* returned value doesn't include room for '\0' */
1005 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1006 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1008 dlen = datalen;
1009 vlen = valuelen;
1010 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1011 &dlen) == ERROR_SUCCESS) {
1012 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1014 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1015 split_subst_info(&psub->from, value);
1016 split_subst_info(&psub->to, data);
1018 /* Win 2000 doesn't allow mapping between different charsets
1019 or mapping of DEFAULT_CHARSET */
1020 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1021 psub->to.charset == DEFAULT_CHARSET) {
1022 HeapFree(GetProcessHeap(), 0, psub->to.name);
1023 HeapFree(GetProcessHeap(), 0, psub->from.name);
1024 HeapFree(GetProcessHeap(), 0, psub);
1025 } else {
1026 add_font_subst(&font_subst_list, psub, 0);
1028 /* reset dlen and vlen */
1029 dlen = datalen;
1030 vlen = valuelen;
1032 HeapFree(GetProcessHeap(), 0, data);
1033 HeapFree(GetProcessHeap(), 0, value);
1034 RegCloseKey(hkey);
1039 /*****************************************************************
1040 * get_name_table_entry
1042 * Supply the platform, encoding, language and name ids in req
1043 * and if the name exists the function will fill in the string
1044 * and string_len members. The string is owned by FreeType so
1045 * don't free it. Returns TRUE if the name is found else FALSE.
1047 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1049 FT_SfntName name;
1050 FT_UInt num_names, name_index;
1052 if(FT_IS_SFNT(ft_face))
1054 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1056 for(name_index = 0; name_index < num_names; name_index++)
1058 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1060 if((name.platform_id == req->platform_id) &&
1061 (name.encoding_id == req->encoding_id) &&
1062 (name.language_id == req->language_id) &&
1063 (name.name_id == req->name_id))
1065 req->string = name.string;
1066 req->string_len = name.string_len;
1067 return TRUE;
1072 req->string = NULL;
1073 req->string_len = 0;
1074 return FALSE;
1077 static WCHAR *get_familyname(FT_Face ft_face)
1079 WCHAR *family = NULL;
1080 FT_SfntName name;
1082 name.platform_id = TT_PLATFORM_MICROSOFT;
1083 name.encoding_id = TT_MS_ID_UNICODE_CS;
1084 name.language_id = GetUserDefaultLCID();
1085 name.name_id = TT_NAME_ID_FONT_FAMILY;
1087 if(get_name_table_entry(ft_face, &name))
1089 FT_UInt i;
1091 /* String is not nul terminated and string_len is a byte length. */
1092 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1093 for(i = 0; i < name.string_len / 2; i++)
1095 WORD *tmp = (WORD *)&name.string[i * 2];
1096 family[i] = GET_BE_WORD(*tmp);
1098 family[i] = 0;
1099 TRACE("Got localised name %s\n", debugstr_w(family));
1102 return family;
1106 /*****************************************************************
1107 * load_sfnt_table
1109 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1110 * of FreeType that don't export this function.
1113 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1116 FT_Error err;
1118 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1119 if(pFT_Load_Sfnt_Table)
1121 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1124 else /* Do it the hard way */
1126 TT_Face tt_face = (TT_Face) ft_face;
1127 SFNT_Interface *sfnt;
1128 if (FT_Version.major==2 && FT_Version.minor==0)
1130 /* 2.0.x */
1131 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1133 else
1135 /* A field was added in the middle of the structure in 2.1.x */
1136 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1138 err = sfnt->load_any(tt_face, table, offset, buf, len);
1140 #else
1141 else
1143 static int msg;
1144 if(!msg)
1146 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1147 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1148 "Please upgrade your freetype library.\n");
1149 msg++;
1151 err = FT_Err_Unimplemented_Feature;
1153 #endif
1154 return err;
1157 static inline int TestStyles(DWORD flags, DWORD styles)
1159 return (flags & styles) == styles;
1162 static int StyleOrdering(Face *face)
1164 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1165 return 3;
1166 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1167 return 2;
1168 if (TestStyles(face->ntmFlags, NTM_BOLD))
1169 return 1;
1170 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1171 return 0;
1173 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1174 debugstr_w(face->family->FamilyName),
1175 debugstr_w(face->StyleName),
1176 face->ntmFlags);
1178 return 9999;
1181 /* Add a style of face to a font family using an ordering of the list such
1182 that regular fonts come before bold and italic, and single styles come
1183 before compound styles. */
1184 static void AddFaceToFamily(Face *face, Family *family)
1186 struct list *entry;
1188 LIST_FOR_EACH( entry, &family->faces )
1190 Face *ent = LIST_ENTRY(entry, Face, entry);
1191 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1193 list_add_before( entry, &face->entry );
1196 #define ADDFONT_EXTERNAL_FONT 0x01
1197 #define ADDFONT_FORCE_BITMAP 0x02
1198 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1200 FT_Face ft_face;
1201 TT_OS2 *pOS2;
1202 TT_Header *pHeader = NULL;
1203 WCHAR *english_family, *localised_family, *StyleW;
1204 DWORD len;
1205 Family *family;
1206 Face *face;
1207 struct list *family_elem_ptr, *face_elem_ptr;
1208 FT_Error err;
1209 FT_Long face_index = 0, num_faces;
1210 #ifdef HAVE_FREETYPE_FTWINFNT_H
1211 FT_WinFNT_HeaderRec winfnt_header;
1212 #endif
1213 int i, bitmap_num, internal_leading;
1214 FONTSIGNATURE fs;
1216 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1217 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1219 #ifdef HAVE_CARBON_CARBON_H
1220 if(file && !fake_family)
1222 char **mac_list = expand_mac_font(file);
1223 if(mac_list)
1225 BOOL had_one = FALSE;
1226 char **cursor;
1227 for(cursor = mac_list; *cursor; cursor++)
1229 had_one = TRUE;
1230 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1231 HeapFree(GetProcessHeap(), 0, *cursor);
1233 HeapFree(GetProcessHeap(), 0, mac_list);
1234 if(had_one)
1235 return 1;
1238 #endif /* HAVE_CARBON_CARBON_H */
1240 do {
1241 char *family_name = fake_family;
1243 if (file)
1245 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1246 err = pFT_New_Face(library, file, face_index, &ft_face);
1247 } else
1249 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1250 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1253 if(err != 0) {
1254 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1255 return 0;
1258 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*/
1259 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1260 pFT_Done_Face(ft_face);
1261 return 0;
1264 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1265 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1266 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1267 pFT_Done_Face(ft_face);
1268 return 0;
1271 if(FT_IS_SFNT(ft_face))
1273 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1274 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1275 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1277 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1278 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1279 pFT_Done_Face(ft_face);
1280 return 0;
1283 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1284 we don't want to load these. */
1285 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1287 FT_ULong len = 0;
1289 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1291 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1292 pFT_Done_Face(ft_face);
1293 return 0;
1298 if(!ft_face->family_name || !ft_face->style_name) {
1299 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1300 pFT_Done_Face(ft_face);
1301 return 0;
1304 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1306 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1307 pFT_Done_Face(ft_face);
1308 return 0;
1311 if (target_family)
1313 localised_family = get_familyname(ft_face);
1314 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1316 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1317 HeapFree(GetProcessHeap(), 0, localised_family);
1318 num_faces = ft_face->num_faces;
1319 pFT_Done_Face(ft_face);
1320 continue;
1322 HeapFree(GetProcessHeap(), 0, localised_family);
1325 if(!family_name)
1326 family_name = ft_face->family_name;
1328 bitmap_num = 0;
1329 do {
1330 My_FT_Bitmap_Size *size = NULL;
1331 FT_ULong tmp_size;
1333 if(!FT_IS_SCALABLE(ft_face))
1334 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1336 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1337 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1338 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1340 localised_family = NULL;
1341 if(!fake_family) {
1342 localised_family = get_familyname(ft_face);
1343 if(localised_family && !strcmpW(localised_family, english_family)) {
1344 HeapFree(GetProcessHeap(), 0, localised_family);
1345 localised_family = NULL;
1349 family = NULL;
1350 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1351 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1352 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1353 break;
1354 family = NULL;
1356 if(!family) {
1357 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1358 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1359 list_init(&family->faces);
1360 list_add_tail(&font_list, &family->entry);
1362 if(localised_family) {
1363 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1364 subst->from.name = strdupW(english_family);
1365 subst->from.charset = -1;
1366 subst->to.name = strdupW(localised_family);
1367 subst->to.charset = -1;
1368 add_font_subst(&font_subst_list, subst, 0);
1371 HeapFree(GetProcessHeap(), 0, localised_family);
1372 HeapFree(GetProcessHeap(), 0, english_family);
1374 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1375 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1376 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1378 internal_leading = 0;
1379 memset(&fs, 0, sizeof(fs));
1381 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1382 if(pOS2) {
1383 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1384 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1385 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1386 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1387 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1388 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1389 if(pOS2->version == 0) {
1390 FT_UInt dummy;
1392 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1393 fs.fsCsb[0] |= FS_LATIN1;
1394 else
1395 fs.fsCsb[0] |= FS_SYMBOL;
1398 #ifdef HAVE_FREETYPE_FTWINFNT_H
1399 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1400 CHARSETINFO csi;
1401 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1402 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1403 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1404 fs = csi.fs;
1405 internal_leading = winfnt_header.internal_leading;
1407 #endif
1409 face_elem_ptr = list_head(&family->faces);
1410 while(face_elem_ptr) {
1411 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1412 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1413 if(!strcmpW(face->StyleName, StyleW) &&
1414 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1415 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1416 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1417 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1419 if(fake_family) {
1420 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1421 HeapFree(GetProcessHeap(), 0, StyleW);
1422 pFT_Done_Face(ft_face);
1423 return 1;
1425 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1426 TRACE("Original font is newer so skipping this one\n");
1427 HeapFree(GetProcessHeap(), 0, StyleW);
1428 pFT_Done_Face(ft_face);
1429 return 1;
1430 } else {
1431 TRACE("Replacing original with this one\n");
1432 list_remove(&face->entry);
1433 HeapFree(GetProcessHeap(), 0, face->file);
1434 HeapFree(GetProcessHeap(), 0, face->StyleName);
1435 HeapFree(GetProcessHeap(), 0, face);
1436 break;
1440 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1441 face->cached_enum_data = NULL;
1442 face->StyleName = StyleW;
1443 if (file)
1445 face->file = strdupA(file);
1446 face->font_data_ptr = NULL;
1447 face->font_data_size = 0;
1449 else
1451 face->file = NULL;
1452 face->font_data_ptr = font_data_ptr;
1453 face->font_data_size = font_data_size;
1455 face->face_index = face_index;
1456 face->ntmFlags = 0;
1457 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1458 face->ntmFlags |= NTM_ITALIC;
1459 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1460 face->ntmFlags |= NTM_BOLD;
1461 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1462 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1463 face->family = family;
1464 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1465 face->fs = fs;
1466 memset(&face->fs_links, 0, sizeof(face->fs_links));
1468 if(FT_IS_SCALABLE(ft_face)) {
1469 memset(&face->size, 0, sizeof(face->size));
1470 face->scalable = TRUE;
1471 } else {
1472 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1473 size->height, size->width, size->size >> 6,
1474 size->x_ppem >> 6, size->y_ppem >> 6);
1475 face->size.height = size->height;
1476 face->size.width = size->width;
1477 face->size.size = size->size;
1478 face->size.x_ppem = size->x_ppem;
1479 face->size.y_ppem = size->y_ppem;
1480 face->size.internal_leading = internal_leading;
1481 face->scalable = FALSE;
1484 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1485 tmp_size = 0;
1486 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1488 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1489 face->ntmFlags |= NTM_PS_OPENTYPE;
1492 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1493 face->fs.fsCsb[0], face->fs.fsCsb[1],
1494 face->fs.fsUsb[0], face->fs.fsUsb[1],
1495 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1498 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1499 for(i = 0; i < ft_face->num_charmaps; i++) {
1500 switch(ft_face->charmaps[i]->encoding) {
1501 case FT_ENCODING_UNICODE:
1502 case FT_ENCODING_APPLE_ROMAN:
1503 face->fs.fsCsb[0] |= FS_LATIN1;
1504 break;
1505 case FT_ENCODING_MS_SYMBOL:
1506 face->fs.fsCsb[0] |= FS_SYMBOL;
1507 break;
1508 default:
1509 break;
1514 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1515 have_installed_roman_font = TRUE;
1517 AddFaceToFamily(face, family);
1519 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1521 num_faces = ft_face->num_faces;
1522 pFT_Done_Face(ft_face);
1523 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1524 debugstr_w(StyleW));
1525 } while(num_faces > ++face_index);
1526 return num_faces;
1529 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1531 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1534 static void DumpFontList(void)
1536 Family *family;
1537 Face *face;
1538 struct list *family_elem_ptr, *face_elem_ptr;
1540 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1541 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1542 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1543 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1544 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1545 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1546 if(!face->scalable)
1547 TRACE(" %d", face->size.height);
1548 TRACE("\n");
1551 return;
1554 /***********************************************************
1555 * The replacement list is a way to map an entire font
1556 * family onto another family. For example adding
1558 * [HKCU\Software\Wine\Fonts\Replacements]
1559 * "Wingdings"="Winedings"
1561 * would enumerate the Winedings font both as Winedings and
1562 * Wingdings. However if a real Wingdings font is present the
1563 * replacement does not take place.
1566 static void LoadReplaceList(void)
1568 HKEY hkey;
1569 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1570 LPWSTR value;
1571 LPVOID data;
1572 Family *family;
1573 Face *face;
1574 struct list *family_elem_ptr, *face_elem_ptr;
1575 CHAR familyA[400];
1577 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1578 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1580 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1581 &valuelen, &datalen, NULL, NULL);
1583 valuelen++; /* returned value doesn't include room for '\0' */
1584 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1585 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1587 dlen = datalen;
1588 vlen = valuelen;
1589 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1590 &dlen) == ERROR_SUCCESS) {
1591 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1592 /* "NewName"="Oldname" */
1593 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1595 /* Find the old family and hence all of the font files
1596 in that family */
1597 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1598 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1599 if(!strcmpiW(family->FamilyName, data)) {
1600 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1601 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1602 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1603 debugstr_w(face->StyleName), familyA);
1604 /* Now add a new entry with the new family name */
1605 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1607 break;
1610 /* reset dlen and vlen */
1611 dlen = datalen;
1612 vlen = valuelen;
1614 HeapFree(GetProcessHeap(), 0, data);
1615 HeapFree(GetProcessHeap(), 0, value);
1616 RegCloseKey(hkey);
1620 /*************************************************************
1621 * init_system_links
1623 static BOOL init_system_links(void)
1625 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1626 'W','i','n','d','o','w','s',' ','N','T','\\',
1627 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1628 'S','y','s','t','e','m','L','i','n','k',0};
1629 HKEY hkey;
1630 BOOL ret = FALSE;
1631 DWORD type, max_val, max_data, val_len, data_len, index;
1632 WCHAR *value, *data;
1633 WCHAR *entry, *next;
1634 SYSTEM_LINKS *font_link, *system_font_link;
1635 CHILD_FONT *child_font;
1636 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1637 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1638 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1639 FONTSIGNATURE fs;
1640 Family *family;
1641 Face *face;
1642 FontSubst *psub;
1644 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1646 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1647 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1648 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1649 val_len = max_val + 1;
1650 data_len = max_data;
1651 index = 0;
1652 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1654 TRACE("%s:\n", debugstr_w(value));
1656 memset(&fs, 0, sizeof(fs));
1657 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1658 psub = get_font_subst(&font_subst_list, value, -1);
1659 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1660 list_init(&font_link->links);
1661 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1663 WCHAR *face_name;
1664 CHILD_FONT *child_font;
1666 TRACE("\t%s\n", debugstr_w(entry));
1668 next = entry + strlenW(entry) + 1;
1670 face_name = strchrW(entry, ',');
1671 if(face_name)
1673 *face_name++ = 0;
1674 while(isspaceW(*face_name))
1675 face_name++;
1677 psub = get_font_subst(&font_subst_list, face_name, -1);
1678 if(psub)
1679 face_name = psub->to.name;
1681 face = find_face_from_filename(entry, face_name);
1682 if(!face)
1684 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1685 continue;
1688 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1689 child_font->face = face;
1690 child_font->font = NULL;
1691 fs.fsCsb[0] |= face->fs.fsCsb[0];
1692 fs.fsCsb[1] |= face->fs.fsCsb[1];
1693 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1694 list_add_tail(&font_link->links, &child_font->entry);
1696 family = find_family_from_name(font_link->font_name);
1697 if(family)
1699 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1701 face->fs_links = fs;
1704 list_add_tail(&system_links, &font_link->entry);
1705 val_len = max_val + 1;
1706 data_len = max_data;
1709 HeapFree(GetProcessHeap(), 0, value);
1710 HeapFree(GetProcessHeap(), 0, data);
1711 RegCloseKey(hkey);
1714 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1715 that Tahoma has */
1717 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1718 system_font_link->font_name = strdupW(System);
1719 list_init(&system_font_link->links);
1721 face = find_face_from_filename(tahoma_ttf, Tahoma);
1722 if(face)
1724 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1725 child_font->face = face;
1726 child_font->font = NULL;
1727 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1728 list_add_tail(&system_font_link->links, &child_font->entry);
1730 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1732 if(!strcmpiW(font_link->font_name, Tahoma))
1734 CHILD_FONT *font_link_entry;
1735 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1737 CHILD_FONT *new_child;
1738 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1739 new_child->face = font_link_entry->face;
1740 new_child->font = NULL;
1741 list_add_tail(&system_font_link->links, &new_child->entry);
1743 break;
1746 list_add_tail(&system_links, &system_font_link->entry);
1747 return ret;
1750 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1752 DIR *dir;
1753 struct dirent *dent;
1754 char path[MAX_PATH];
1756 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1758 dir = opendir(dirname);
1759 if(!dir) {
1760 WARN("Can't open directory %s\n", debugstr_a(dirname));
1761 return FALSE;
1763 while((dent = readdir(dir)) != NULL) {
1764 struct stat statbuf;
1766 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1767 continue;
1769 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1771 sprintf(path, "%s/%s", dirname, dent->d_name);
1773 if(stat(path, &statbuf) == -1)
1775 WARN("Can't stat %s\n", debugstr_a(path));
1776 continue;
1778 if(S_ISDIR(statbuf.st_mode))
1779 ReadFontDir(path, external_fonts);
1780 else
1781 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1783 closedir(dir);
1784 return TRUE;
1787 static void load_fontconfig_fonts(void)
1789 #ifdef SONAME_LIBFONTCONFIG
1790 void *fc_handle = NULL;
1791 FcConfig *config;
1792 FcPattern *pat;
1793 FcObjectSet *os;
1794 FcFontSet *fontset;
1795 int i, len;
1796 char *file;
1797 const char *ext;
1799 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1800 if(!fc_handle) {
1801 TRACE("Wine cannot find the fontconfig library (%s).\n",
1802 SONAME_LIBFONTCONFIG);
1803 return;
1805 #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;}
1806 LOAD_FUNCPTR(FcConfigGetCurrent);
1807 LOAD_FUNCPTR(FcFontList);
1808 LOAD_FUNCPTR(FcFontSetDestroy);
1809 LOAD_FUNCPTR(FcInit);
1810 LOAD_FUNCPTR(FcObjectSetAdd);
1811 LOAD_FUNCPTR(FcObjectSetCreate);
1812 LOAD_FUNCPTR(FcObjectSetDestroy);
1813 LOAD_FUNCPTR(FcPatternCreate);
1814 LOAD_FUNCPTR(FcPatternDestroy);
1815 LOAD_FUNCPTR(FcPatternGetBool);
1816 LOAD_FUNCPTR(FcPatternGetString);
1817 #undef LOAD_FUNCPTR
1819 if(!pFcInit()) return;
1821 config = pFcConfigGetCurrent();
1822 pat = pFcPatternCreate();
1823 os = pFcObjectSetCreate();
1824 pFcObjectSetAdd(os, FC_FILE);
1825 pFcObjectSetAdd(os, FC_SCALABLE);
1826 fontset = pFcFontList(config, pat, os);
1827 if(!fontset) return;
1828 for(i = 0; i < fontset->nfont; i++) {
1829 FcBool scalable;
1831 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1832 continue;
1833 TRACE("fontconfig: %s\n", file);
1835 /* We're just interested in OT/TT fonts for now, so this hack just
1836 picks up the scalable fonts without extensions .pf[ab] to save time
1837 loading every other font */
1839 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1841 TRACE("not scalable\n");
1842 continue;
1845 len = strlen( file );
1846 if(len < 4) continue;
1847 ext = &file[ len - 3 ];
1848 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1849 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1851 pFcFontSetDestroy(fontset);
1852 pFcObjectSetDestroy(os);
1853 pFcPatternDestroy(pat);
1854 sym_not_found:
1855 #endif
1856 return;
1859 static BOOL load_font_from_data_dir(LPCWSTR file)
1861 BOOL ret = FALSE;
1862 const char *data_dir = wine_get_data_dir();
1864 if (!data_dir) data_dir = wine_get_build_dir();
1866 if (data_dir)
1868 INT len;
1869 char *unix_name;
1871 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1873 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1875 strcpy(unix_name, data_dir);
1876 strcat(unix_name, "/fonts/");
1878 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1880 EnterCriticalSection( &freetype_cs );
1881 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1882 LeaveCriticalSection( &freetype_cs );
1883 HeapFree(GetProcessHeap(), 0, unix_name);
1885 return ret;
1888 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1890 static const WCHAR slashW[] = {'\\','\0'};
1891 BOOL ret = FALSE;
1892 WCHAR windowsdir[MAX_PATH];
1893 char *unixname;
1895 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1896 strcatW(windowsdir, fontsW);
1897 strcatW(windowsdir, slashW);
1898 strcatW(windowsdir, file);
1899 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1900 EnterCriticalSection( &freetype_cs );
1901 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1902 LeaveCriticalSection( &freetype_cs );
1903 HeapFree(GetProcessHeap(), 0, unixname);
1905 return ret;
1908 static void load_system_fonts(void)
1910 HKEY hkey;
1911 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1912 const WCHAR * const *value;
1913 DWORD dlen, type;
1914 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1915 char *unixname;
1917 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1918 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1919 strcatW(windowsdir, fontsW);
1920 for(value = SystemFontValues; *value; value++) {
1921 dlen = sizeof(data);
1922 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1923 type == REG_SZ) {
1924 BOOL added = FALSE;
1926 sprintfW(pathW, fmtW, windowsdir, data);
1927 if((unixname = wine_get_unix_file_name(pathW))) {
1928 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1929 HeapFree(GetProcessHeap(), 0, unixname);
1931 if (!added)
1932 load_font_from_data_dir(data);
1935 RegCloseKey(hkey);
1939 /*************************************************************
1941 * This adds registry entries for any externally loaded fonts
1942 * (fonts from fontconfig or FontDirs). It also deletes entries
1943 * of no longer existing fonts.
1946 static void update_reg_entries(void)
1948 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1949 LPWSTR valueW;
1950 DWORD len, len_fam;
1951 Family *family;
1952 Face *face;
1953 struct list *family_elem_ptr, *face_elem_ptr;
1954 WCHAR *file;
1955 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1956 static const WCHAR spaceW[] = {' ', '\0'};
1957 char *path;
1959 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1960 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1961 ERR("Can't create Windows font reg key\n");
1962 goto end;
1965 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1966 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1967 ERR("Can't create Windows font reg key\n");
1968 goto end;
1971 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1972 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1973 ERR("Can't create external font reg key\n");
1974 goto end;
1977 /* enumerate the fonts and add external ones to the two keys */
1979 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1980 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1981 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1982 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1983 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1984 if(!face->external) continue;
1985 len = len_fam;
1986 if (!(face->ntmFlags & NTM_REGULAR))
1987 len = len_fam + strlenW(face->StyleName) + 1;
1988 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1989 strcpyW(valueW, family->FamilyName);
1990 if(len != len_fam) {
1991 strcatW(valueW, spaceW);
1992 strcatW(valueW, face->StyleName);
1994 strcatW(valueW, TrueType);
1996 file = wine_get_dos_file_name(face->file);
1997 if(file)
1998 len = strlenW(file) + 1;
1999 else
2001 if((path = strrchr(face->file, '/')) == NULL)
2002 path = face->file;
2003 else
2004 path++;
2005 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2007 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2008 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2010 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2011 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2012 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2014 HeapFree(GetProcessHeap(), 0, file);
2015 HeapFree(GetProcessHeap(), 0, valueW);
2018 end:
2019 if(external_key) RegCloseKey(external_key);
2020 if(win9x_key) RegCloseKey(win9x_key);
2021 if(winnt_key) RegCloseKey(winnt_key);
2022 return;
2025 static void delete_external_font_keys(void)
2027 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2028 DWORD dlen, vlen, datalen, valuelen, i, type;
2029 LPWSTR valueW;
2030 LPVOID data;
2032 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2033 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2034 ERR("Can't create Windows font reg key\n");
2035 goto end;
2038 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2039 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2040 ERR("Can't create Windows font reg key\n");
2041 goto end;
2044 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2045 ERR("Can't create external font reg key\n");
2046 goto end;
2049 /* Delete all external fonts added last time */
2051 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2052 &valuelen, &datalen, NULL, NULL);
2053 valuelen++; /* returned value doesn't include room for '\0' */
2054 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2055 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2057 dlen = datalen * sizeof(WCHAR);
2058 vlen = valuelen;
2059 i = 0;
2060 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2061 &dlen) == ERROR_SUCCESS) {
2063 RegDeleteValueW(winnt_key, valueW);
2064 RegDeleteValueW(win9x_key, valueW);
2065 /* reset dlen and vlen */
2066 dlen = datalen;
2067 vlen = valuelen;
2069 HeapFree(GetProcessHeap(), 0, data);
2070 HeapFree(GetProcessHeap(), 0, valueW);
2072 /* Delete the old external fonts key */
2073 RegCloseKey(external_key);
2074 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2076 end:
2077 if(win9x_key) RegCloseKey(win9x_key);
2078 if(winnt_key) RegCloseKey(winnt_key);
2081 /*************************************************************
2082 * WineEngAddFontResourceEx
2085 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2087 INT ret = 0;
2088 if (ft_handle) /* do it only if we have freetype up and running */
2090 char *unixname;
2092 if(flags)
2093 FIXME("Ignoring flags %x\n", flags);
2095 if((unixname = wine_get_unix_file_name(file)))
2097 EnterCriticalSection( &freetype_cs );
2098 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2099 LeaveCriticalSection( &freetype_cs );
2100 HeapFree(GetProcessHeap(), 0, unixname);
2102 if (!ret && !strchrW(file, '\\')) {
2103 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2104 ret = load_font_from_winfonts_dir(file);
2105 if (!ret) {
2106 /* Try in datadir/fonts (or builddir/fonts),
2107 * needed for Magic the Gathering Online
2109 ret = load_font_from_data_dir(file);
2113 return ret;
2116 /*************************************************************
2117 * WineEngAddFontMemResourceEx
2120 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2122 if (ft_handle) /* do it only if we have freetype up and running */
2124 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2126 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2127 memcpy(pFontCopy, pbFont, cbFont);
2129 EnterCriticalSection( &freetype_cs );
2130 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2131 LeaveCriticalSection( &freetype_cs );
2133 if (*pcFonts == 0)
2135 TRACE("AddFontToList failed\n");
2136 HeapFree(GetProcessHeap(), 0, pFontCopy);
2137 return NULL;
2139 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2140 * For now return something unique but quite random
2142 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2143 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2146 *pcFonts = 0;
2147 return 0;
2150 /*************************************************************
2151 * WineEngRemoveFontResourceEx
2154 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2156 FIXME(":stub\n");
2157 return TRUE;
2160 static const struct nls_update_font_list
2162 UINT ansi_cp, oem_cp;
2163 const char *oem, *fixed, *system;
2164 const char *courier, *serif, *small, *sserif;
2165 /* these are for font substitutes */
2166 const char *shelldlg, *tmsrmn;
2167 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2168 *helv_0, *tmsrmn_0;
2169 const struct subst
2171 const char *from, *to;
2172 } arial_0, courier_new_0, times_new_roman_0;
2173 } nls_update_font_list[] =
2175 /* Latin 1 (United States) */
2176 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2177 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2178 "Tahoma","Times New Roman",
2179 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2180 { 0 }, { 0 }, { 0 }
2182 /* Latin 1 (Multilingual) */
2183 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2184 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2185 "Tahoma","Times New Roman", /* FIXME unverified */
2186 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2187 { 0 }, { 0 }, { 0 }
2189 /* Eastern Europe */
2190 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2191 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2192 "Tahoma","Times New Roman", /* FIXME unverified */
2193 "Fixedsys,238", "System,238",
2194 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2195 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2196 { "Arial CE,0", "Arial,238" },
2197 { "Courier New CE,0", "Courier New,238" },
2198 { "Times New Roman CE,0", "Times New Roman,238" }
2200 /* Cyrillic */
2201 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2202 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2203 "Tahoma","Times New Roman", /* FIXME unverified */
2204 "Fixedsys,204", "System,204",
2205 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2206 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2207 { "Arial Cyr,0", "Arial,204" },
2208 { "Courier New Cyr,0", "Courier New,204" },
2209 { "Times New Roman Cyr,0", "Times New Roman,204" }
2211 /* Greek */
2212 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2213 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2214 "Tahoma","Times New Roman", /* FIXME unverified */
2215 "Fixedsys,161", "System,161",
2216 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2217 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2218 { "Arial Greek,0", "Arial,161" },
2219 { "Courier New Greek,0", "Courier New,161" },
2220 { "Times New Roman Greek,0", "Times New Roman,161" }
2222 /* Turkish */
2223 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2224 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2225 "Tahoma","Times New Roman", /* FIXME unverified */
2226 "Fixedsys,162", "System,162",
2227 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2228 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2229 { "Arial Tur,0", "Arial,162" },
2230 { "Courier New Tur,0", "Courier New,162" },
2231 { "Times New Roman Tur,0", "Times New Roman,162" }
2233 /* Hebrew */
2234 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2235 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2236 "Tahoma","Times New Roman", /* FIXME unverified */
2237 "Fixedsys,177", "System,177",
2238 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2239 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2240 { 0 }, { 0 }, { 0 }
2242 /* Arabic */
2243 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2244 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,178", "System,178",
2247 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2248 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2249 { 0 }, { 0 }, { 0 }
2251 /* Baltic */
2252 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2253 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2254 "Tahoma","Times New Roman", /* FIXME unverified */
2255 "Fixedsys,186", "System,186",
2256 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2257 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2258 { "Arial Baltic,0", "Arial,186" },
2259 { "Courier New Baltic,0", "Courier New,186" },
2260 { "Times New Roman Baltic,0", "Times New Roman,186" }
2262 /* Vietnamese */
2263 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2264 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2265 "Tahoma","Times New Roman", /* FIXME unverified */
2266 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2267 { 0 }, { 0 }, { 0 }
2269 /* Thai */
2270 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2271 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2272 "Tahoma","Times New Roman", /* FIXME unverified */
2273 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2274 { 0 }, { 0 }, { 0 }
2276 /* Japanese */
2277 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2278 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2279 "MS UI Gothic","MS Serif",
2280 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2281 { 0 }, { 0 }, { 0 }
2283 /* Chinese Simplified */
2284 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2285 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2286 "SimSun", "NSimSun",
2287 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2288 { 0 }, { 0 }, { 0 }
2290 /* Korean */
2291 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2292 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2293 "Gulim", "Batang",
2294 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2295 { 0 }, { 0 }, { 0 }
2297 /* Chinese Traditional */
2298 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2299 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2300 "PMingLiU", "MingLiU",
2301 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2302 { 0 }, { 0 }, { 0 }
2306 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2308 return ( ansi_cp == 932 /* CP932 for Japanese */
2309 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2310 || ansi_cp == 949 /* CP949 for Korean */
2311 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2314 static inline HKEY create_fonts_NT_registry_key(void)
2316 HKEY hkey = 0;
2318 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2319 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2320 return hkey;
2323 static inline HKEY create_fonts_9x_registry_key(void)
2325 HKEY hkey = 0;
2327 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2328 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2329 return hkey;
2332 static inline HKEY create_config_fonts_registry_key(void)
2334 HKEY hkey = 0;
2336 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2337 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2338 return hkey;
2341 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2343 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2344 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2345 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2346 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2349 static void set_value_key(HKEY hkey, const char *name, const char *value)
2351 if (value)
2352 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2353 else if (name)
2354 RegDeleteValueA(hkey, name);
2357 static void update_font_info(void)
2359 char buf[40], cpbuf[40];
2360 DWORD len, type;
2361 HKEY hkey = 0;
2362 UINT i, ansi_cp = 0, oem_cp = 0;
2363 BOOL done = FALSE;
2365 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2366 return;
2368 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2369 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2370 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2371 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2372 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2374 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2375 if (is_dbcs_ansi_cp(ansi_cp))
2376 use_default_fallback = TRUE;
2378 len = sizeof(buf);
2379 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2381 if (!strcmp( buf, cpbuf )) /* already set correctly */
2383 RegCloseKey(hkey);
2384 return;
2386 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2388 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2390 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2391 RegCloseKey(hkey);
2393 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2395 HKEY hkey;
2397 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2398 nls_update_font_list[i].oem_cp == oem_cp)
2400 hkey = create_config_fonts_registry_key();
2401 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2402 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2403 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2404 RegCloseKey(hkey);
2406 hkey = create_fonts_NT_registry_key();
2407 add_font_list(hkey, &nls_update_font_list[i]);
2408 RegCloseKey(hkey);
2410 hkey = create_fonts_9x_registry_key();
2411 add_font_list(hkey, &nls_update_font_list[i]);
2412 RegCloseKey(hkey);
2414 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2416 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2417 strlen(nls_update_font_list[i].shelldlg)+1);
2418 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2419 strlen(nls_update_font_list[i].tmsrmn)+1);
2421 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2422 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2423 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2424 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2425 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2426 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2427 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2428 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2430 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2431 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2432 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2434 RegCloseKey(hkey);
2436 done = TRUE;
2438 else
2440 /* Delete the FontSubstitutes from other locales */
2441 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2443 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2444 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2445 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2446 RegCloseKey(hkey);
2450 if (!done)
2451 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2455 static BOOL init_freetype(void)
2457 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2458 if(!ft_handle) {
2459 WINE_MESSAGE(
2460 "Wine cannot find the FreeType font library. To enable Wine to\n"
2461 "use TrueType fonts please install a version of FreeType greater than\n"
2462 "or equal to 2.0.5.\n"
2463 "http://www.freetype.org\n");
2464 return FALSE;
2467 #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;}
2469 LOAD_FUNCPTR(FT_Vector_Unit)
2470 LOAD_FUNCPTR(FT_Done_Face)
2471 LOAD_FUNCPTR(FT_Get_Char_Index)
2472 LOAD_FUNCPTR(FT_Get_Module)
2473 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2474 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2475 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2476 LOAD_FUNCPTR(FT_Init_FreeType)
2477 LOAD_FUNCPTR(FT_Load_Glyph)
2478 LOAD_FUNCPTR(FT_Matrix_Multiply)
2479 #ifndef FT_MULFIX_INLINED
2480 LOAD_FUNCPTR(FT_MulFix)
2481 #endif
2482 LOAD_FUNCPTR(FT_New_Face)
2483 LOAD_FUNCPTR(FT_New_Memory_Face)
2484 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2485 LOAD_FUNCPTR(FT_Outline_Transform)
2486 LOAD_FUNCPTR(FT_Outline_Translate)
2487 LOAD_FUNCPTR(FT_Select_Charmap)
2488 LOAD_FUNCPTR(FT_Set_Charmap)
2489 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2490 LOAD_FUNCPTR(FT_Vector_Transform)
2491 LOAD_FUNCPTR(FT_Render_Glyph)
2493 #undef LOAD_FUNCPTR
2494 /* Don't warn if these ones are missing */
2495 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2496 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2497 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2498 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2499 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2500 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2501 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2502 #endif
2503 #ifdef HAVE_FREETYPE_FTWINFNT_H
2504 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2505 #endif
2506 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2507 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2508 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2509 <= 2.0.3 has FT_Sqrt64 */
2510 goto sym_not_found;
2513 if(pFT_Init_FreeType(&library) != 0) {
2514 ERR("Can't init FreeType library\n");
2515 wine_dlclose(ft_handle, NULL, 0);
2516 ft_handle = NULL;
2517 return FALSE;
2519 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2520 if (pFT_Library_Version)
2521 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2523 if (FT_Version.major<=0)
2525 FT_Version.major=2;
2526 FT_Version.minor=0;
2527 FT_Version.patch=5;
2529 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2530 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2531 ((FT_Version.minor << 8) & 0x00ff00) |
2532 ((FT_Version.patch ) & 0x0000ff);
2534 return TRUE;
2536 sym_not_found:
2537 WINE_MESSAGE(
2538 "Wine cannot find certain functions that it needs inside the FreeType\n"
2539 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2540 "FreeType to at least version 2.0.5.\n"
2541 "http://www.freetype.org\n");
2542 wine_dlclose(ft_handle, NULL, 0);
2543 ft_handle = NULL;
2544 return FALSE;
2547 /*************************************************************
2548 * WineEngInit
2550 * Initialize FreeType library and create a list of available faces
2552 BOOL WineEngInit(void)
2554 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2555 static const WCHAR pathW[] = {'P','a','t','h',0};
2556 HKEY hkey;
2557 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2558 WCHAR windowsdir[MAX_PATH];
2559 char *unixname;
2560 HANDLE font_mutex;
2561 const char *data_dir;
2563 TRACE("\n");
2565 /* update locale dependent font info in registry */
2566 update_font_info();
2568 if(!init_freetype()) return FALSE;
2570 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2571 ERR("Failed to create font mutex\n");
2572 return FALSE;
2574 WaitForSingleObject(font_mutex, INFINITE);
2576 delete_external_font_keys();
2578 /* load the system bitmap fonts */
2579 load_system_fonts();
2581 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2582 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2583 strcatW(windowsdir, fontsW);
2584 if((unixname = wine_get_unix_file_name(windowsdir)))
2586 ReadFontDir(unixname, FALSE);
2587 HeapFree(GetProcessHeap(), 0, unixname);
2590 /* load the system truetype fonts */
2591 data_dir = wine_get_data_dir();
2592 if (!data_dir) data_dir = wine_get_build_dir();
2593 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2594 strcpy(unixname, data_dir);
2595 strcat(unixname, "/fonts/");
2596 ReadFontDir(unixname, TRUE);
2597 HeapFree(GetProcessHeap(), 0, unixname);
2600 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2601 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2602 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2603 will skip these. */
2604 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2605 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2606 &hkey) == ERROR_SUCCESS) {
2607 LPWSTR data, valueW;
2608 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2609 &valuelen, &datalen, NULL, NULL);
2611 valuelen++; /* returned value doesn't include room for '\0' */
2612 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2613 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2614 if (valueW && data)
2616 dlen = datalen * sizeof(WCHAR);
2617 vlen = valuelen;
2618 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2619 &dlen) == ERROR_SUCCESS) {
2620 if(data[0] && (data[1] == ':'))
2622 if((unixname = wine_get_unix_file_name(data)))
2624 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2625 HeapFree(GetProcessHeap(), 0, unixname);
2628 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2630 WCHAR pathW[MAX_PATH];
2631 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2632 BOOL added = FALSE;
2634 sprintfW(pathW, fmtW, windowsdir, data);
2635 if((unixname = wine_get_unix_file_name(pathW)))
2637 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2638 HeapFree(GetProcessHeap(), 0, unixname);
2640 if (!added)
2641 load_font_from_data_dir(data);
2643 /* reset dlen and vlen */
2644 dlen = datalen;
2645 vlen = valuelen;
2648 HeapFree(GetProcessHeap(), 0, data);
2649 HeapFree(GetProcessHeap(), 0, valueW);
2650 RegCloseKey(hkey);
2653 load_fontconfig_fonts();
2655 /* then look in any directories that we've specified in the config file */
2656 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2657 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2659 DWORD len;
2660 LPWSTR valueW;
2661 LPSTR valueA, ptr;
2663 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2665 len += sizeof(WCHAR);
2666 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2667 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2669 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2670 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2671 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2672 TRACE( "got font path %s\n", debugstr_a(valueA) );
2673 ptr = valueA;
2674 while (ptr)
2676 LPSTR next = strchr( ptr, ':' );
2677 if (next) *next++ = 0;
2678 ReadFontDir( ptr, TRUE );
2679 ptr = next;
2681 HeapFree( GetProcessHeap(), 0, valueA );
2683 HeapFree( GetProcessHeap(), 0, valueW );
2685 RegCloseKey(hkey);
2688 DumpFontList();
2689 LoadSubstList();
2690 DumpSubstList();
2691 LoadReplaceList();
2692 update_reg_entries();
2694 init_system_links();
2696 ReleaseMutex(font_mutex);
2697 return TRUE;
2701 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2703 TT_OS2 *pOS2;
2704 TT_HoriHeader *pHori;
2706 LONG ppem;
2708 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2709 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2711 if(height == 0) height = 16;
2713 /* Calc. height of EM square:
2715 * For +ve lfHeight we have
2716 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2717 * Re-arranging gives:
2718 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2720 * For -ve lfHeight we have
2721 * |lfHeight| = ppem
2722 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2723 * with il = winAscent + winDescent - units_per_em]
2727 if(height > 0) {
2728 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2729 ppem = MulDiv(ft_face->units_per_EM, height,
2730 pHori->Ascender - pHori->Descender);
2731 else
2732 ppem = MulDiv(ft_face->units_per_EM, height,
2733 pOS2->usWinAscent + pOS2->usWinDescent);
2735 else
2736 ppem = -height;
2738 return ppem;
2741 static struct font_mapping *map_font_file( const char *name )
2743 struct font_mapping *mapping;
2744 struct stat st;
2745 int fd;
2747 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2748 if (fstat( fd, &st ) == -1) goto error;
2750 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2752 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2754 mapping->refcount++;
2755 close( fd );
2756 return mapping;
2759 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2760 goto error;
2762 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2763 close( fd );
2765 if (mapping->data == MAP_FAILED)
2767 HeapFree( GetProcessHeap(), 0, mapping );
2768 return NULL;
2770 mapping->refcount = 1;
2771 mapping->dev = st.st_dev;
2772 mapping->ino = st.st_ino;
2773 mapping->size = st.st_size;
2774 list_add_tail( &mappings_list, &mapping->entry );
2775 return mapping;
2777 error:
2778 close( fd );
2779 return NULL;
2782 static void unmap_font_file( struct font_mapping *mapping )
2784 if (!--mapping->refcount)
2786 list_remove( &mapping->entry );
2787 munmap( mapping->data, mapping->size );
2788 HeapFree( GetProcessHeap(), 0, mapping );
2792 static LONG load_VDMX(GdiFont*, LONG);
2794 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2796 FT_Error err;
2797 FT_Face ft_face;
2798 void *data_ptr;
2799 DWORD data_size;
2801 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2803 if (face->file)
2805 if (!(font->mapping = map_font_file( face->file )))
2807 WARN("failed to map %s\n", debugstr_a(face->file));
2808 return 0;
2810 data_ptr = font->mapping->data;
2811 data_size = font->mapping->size;
2813 else
2815 data_ptr = face->font_data_ptr;
2816 data_size = face->font_data_size;
2819 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2820 if(err) {
2821 ERR("FT_New_Face rets %d\n", err);
2822 return 0;
2825 /* set it here, as load_VDMX needs it */
2826 font->ft_face = ft_face;
2828 if(FT_IS_SCALABLE(ft_face)) {
2829 /* load the VDMX table if we have one */
2830 font->ppem = load_VDMX(font, height);
2831 if(font->ppem == 0)
2832 font->ppem = calc_ppem_for_height(ft_face, height);
2833 TRACE("height %d => ppem %d\n", height, font->ppem);
2835 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2836 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2837 } else {
2838 font->ppem = height;
2839 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2840 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2842 return ft_face;
2846 static int get_nearest_charset(Face *face, int *cp)
2848 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2849 a single face with the requested charset. The idea is to check if
2850 the selected font supports the current ANSI codepage, if it does
2851 return the corresponding charset, else return the first charset */
2853 CHARSETINFO csi;
2854 int acp = GetACP(), i;
2855 DWORD fs0;
2857 *cp = acp;
2858 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2859 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2860 return csi.ciCharset;
2862 for(i = 0; i < 32; i++) {
2863 fs0 = 1L << i;
2864 if(face->fs.fsCsb[0] & fs0) {
2865 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2866 *cp = csi.ciACP;
2867 return csi.ciCharset;
2869 else
2870 FIXME("TCI failing on %x\n", fs0);
2874 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2875 face->fs.fsCsb[0], face->file);
2876 *cp = acp;
2877 return DEFAULT_CHARSET;
2880 static GdiFont *alloc_font(void)
2882 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2883 ret->gmsize = 1;
2884 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2885 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2886 ret->potm = NULL;
2887 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2888 ret->total_kern_pairs = (DWORD)-1;
2889 ret->kern_pairs = NULL;
2890 list_init(&ret->hfontlist);
2891 list_init(&ret->child_fonts);
2892 return ret;
2895 static void free_font(GdiFont *font)
2897 struct list *cursor, *cursor2;
2898 DWORD i;
2900 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2902 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2903 struct list *first_hfont;
2904 HFONTLIST *hfontlist;
2905 list_remove(cursor);
2906 if(child->font)
2908 first_hfont = list_head(&child->font->hfontlist);
2909 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2910 DeleteObject(hfontlist->hfont);
2911 HeapFree(GetProcessHeap(), 0, hfontlist);
2912 free_font(child->font);
2914 HeapFree(GetProcessHeap(), 0, child);
2917 if (font->ft_face) pFT_Done_Face(font->ft_face);
2918 if (font->mapping) unmap_font_file( font->mapping );
2919 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2920 HeapFree(GetProcessHeap(), 0, font->potm);
2921 HeapFree(GetProcessHeap(), 0, font->name);
2922 for (i = 0; i < font->gmsize; i++)
2923 HeapFree(GetProcessHeap(),0,font->gm[i]);
2924 HeapFree(GetProcessHeap(), 0, font->gm);
2925 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2926 HeapFree(GetProcessHeap(), 0, font);
2930 /*************************************************************
2931 * load_VDMX
2933 * load the vdmx entry for the specified height
2936 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2937 ( ( (FT_ULong)_x4 << 24 ) | \
2938 ( (FT_ULong)_x3 << 16 ) | \
2939 ( (FT_ULong)_x2 << 8 ) | \
2940 (FT_ULong)_x1 )
2942 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2944 typedef struct {
2945 BYTE bCharSet;
2946 BYTE xRatio;
2947 BYTE yStartRatio;
2948 BYTE yEndRatio;
2949 } Ratios;
2951 typedef struct {
2952 WORD recs;
2953 BYTE startsz;
2954 BYTE endsz;
2955 } VDMX_group;
2957 static LONG load_VDMX(GdiFont *font, LONG height)
2959 WORD hdr[3], tmp;
2960 VDMX_group group;
2961 BYTE devXRatio, devYRatio;
2962 USHORT numRecs, numRatios;
2963 DWORD result, offset = -1;
2964 LONG ppem = 0;
2965 int i;
2967 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2969 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2970 return ppem;
2972 /* FIXME: need the real device aspect ratio */
2973 devXRatio = 1;
2974 devYRatio = 1;
2976 numRecs = GET_BE_WORD(hdr[1]);
2977 numRatios = GET_BE_WORD(hdr[2]);
2979 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2980 for(i = 0; i < numRatios; i++) {
2981 Ratios ratio;
2983 offset = (3 * 2) + (i * sizeof(Ratios));
2984 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2985 offset = -1;
2987 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2989 if((ratio.xRatio == 0 &&
2990 ratio.yStartRatio == 0 &&
2991 ratio.yEndRatio == 0) ||
2992 (devXRatio == ratio.xRatio &&
2993 devYRatio >= ratio.yStartRatio &&
2994 devYRatio <= ratio.yEndRatio))
2996 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2997 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2998 offset = GET_BE_WORD(tmp);
2999 break;
3003 if(offset == -1) {
3004 FIXME("No suitable ratio found\n");
3005 return ppem;
3008 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3009 USHORT recs;
3010 BYTE startsz, endsz;
3011 WORD *vTable;
3013 recs = GET_BE_WORD(group.recs);
3014 startsz = group.startsz;
3015 endsz = group.endsz;
3017 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3019 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3020 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3021 if(result == GDI_ERROR) {
3022 FIXME("Failed to retrieve vTable\n");
3023 goto end;
3026 if(height > 0) {
3027 for(i = 0; i < recs; i++) {
3028 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3029 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3030 ppem = GET_BE_WORD(vTable[i * 3]);
3032 if(yMax + -yMin == height) {
3033 font->yMax = yMax;
3034 font->yMin = yMin;
3035 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3036 break;
3038 if(yMax + -yMin > height) {
3039 if(--i < 0) {
3040 ppem = 0;
3041 goto end; /* failed */
3043 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3044 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3045 ppem = GET_BE_WORD(vTable[i * 3]);
3046 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3047 break;
3050 if(!font->yMax) {
3051 ppem = 0;
3052 TRACE("ppem not found for height %d\n", height);
3054 } else {
3055 ppem = -height;
3056 if(ppem < startsz || ppem > endsz)
3057 goto end;
3059 for(i = 0; i < recs; i++) {
3060 USHORT yPelHeight;
3061 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3063 if(yPelHeight > ppem)
3064 break; /* failed */
3066 if(yPelHeight == ppem) {
3067 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3068 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3069 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3070 break;
3074 end:
3075 HeapFree(GetProcessHeap(), 0, vTable);
3078 return ppem;
3081 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3083 if(font->font_desc.hash != fd->hash) return TRUE;
3084 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3085 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3086 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3087 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3090 static void calc_hash(FONT_DESC *pfd)
3092 DWORD hash = 0, *ptr, two_chars;
3093 WORD *pwc;
3094 unsigned int i;
3096 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3097 hash ^= *ptr;
3098 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3099 hash ^= *ptr;
3100 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3101 two_chars = *ptr;
3102 pwc = (WCHAR *)&two_chars;
3103 if(!*pwc) break;
3104 *pwc = toupperW(*pwc);
3105 pwc++;
3106 *pwc = toupperW(*pwc);
3107 hash ^= two_chars;
3108 if(!*pwc) break;
3110 hash ^= !pfd->can_use_bitmap;
3111 pfd->hash = hash;
3112 return;
3115 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3117 GdiFont *ret;
3118 FONT_DESC fd;
3119 HFONTLIST *hflist;
3120 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3122 fd.lf = *plf;
3123 fd.matrix = *pmat;
3124 fd.can_use_bitmap = can_use_bitmap;
3125 calc_hash(&fd);
3127 /* try the child list */
3128 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3129 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3130 if(!fontcmp(ret, &fd)) {
3131 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3132 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3133 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3134 if(hflist->hfont == hfont)
3135 return ret;
3140 /* try the in-use list */
3141 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3142 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3143 if(!fontcmp(ret, &fd)) {
3144 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3145 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3146 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3147 if(hflist->hfont == hfont)
3148 return ret;
3150 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3151 hflist->hfont = hfont;
3152 list_add_head(&ret->hfontlist, &hflist->entry);
3153 return ret;
3157 /* then the unused list */
3158 font_elem_ptr = list_head(&unused_gdi_font_list);
3159 while(font_elem_ptr) {
3160 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3161 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3162 if(!fontcmp(ret, &fd)) {
3163 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3164 assert(list_empty(&ret->hfontlist));
3165 TRACE("Found %p in unused list\n", ret);
3166 list_remove(&ret->entry);
3167 list_add_head(&gdi_font_list, &ret->entry);
3168 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3169 hflist->hfont = hfont;
3170 list_add_head(&ret->hfontlist, &hflist->entry);
3171 return ret;
3174 return NULL;
3177 static void add_to_cache(GdiFont *font)
3179 static DWORD cache_num = 1;
3181 font->cache_num = cache_num++;
3182 list_add_head(&gdi_font_list, &font->entry);
3185 /*************************************************************
3186 * create_child_font_list
3188 static BOOL create_child_font_list(GdiFont *font)
3190 BOOL ret = FALSE;
3191 SYSTEM_LINKS *font_link;
3192 CHILD_FONT *font_link_entry, *new_child;
3194 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3196 if(!strcmpW(font_link->font_name, font->name))
3198 TRACE("found entry in system list\n");
3199 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3201 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3202 new_child->face = font_link_entry->face;
3203 new_child->font = NULL;
3204 list_add_tail(&font->child_fonts, &new_child->entry);
3205 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3207 ret = TRUE;
3208 break;
3212 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3213 * Sans Serif. This is how asian windows get default fallbacks for fonts
3215 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3216 font->charset != OEM_CHARSET &&
3217 strcmpW(font->name,szDefaultFallbackLink) != 0)
3218 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3220 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3222 TRACE("found entry in default fallback list\n");
3223 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3225 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3226 new_child->face = font_link_entry->face;
3227 new_child->font = NULL;
3228 list_add_tail(&font->child_fonts, &new_child->entry);
3229 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3231 ret = TRUE;
3232 break;
3236 return ret;
3239 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3241 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3243 if (pFT_Set_Charmap)
3245 FT_Int i;
3246 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3248 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3250 for (i = 0; i < ft_face->num_charmaps; i++)
3252 if (ft_face->charmaps[i]->encoding == encoding)
3254 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3255 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3257 switch (ft_face->charmaps[i]->platform_id)
3259 default:
3260 cmap_def = ft_face->charmaps[i];
3261 break;
3262 case 0: /* Apple Unicode */
3263 cmap0 = ft_face->charmaps[i];
3264 break;
3265 case 1: /* Macintosh */
3266 cmap1 = ft_face->charmaps[i];
3267 break;
3268 case 2: /* ISO */
3269 cmap2 = ft_face->charmaps[i];
3270 break;
3271 case 3: /* Microsoft */
3272 cmap3 = ft_face->charmaps[i];
3273 break;
3277 if (cmap3) /* prefer Microsoft cmap table */
3278 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3279 else if (cmap1)
3280 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3281 else if (cmap2)
3282 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3283 else if (cmap0)
3284 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3285 else if (cmap_def)
3286 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3288 return ft_err == FT_Err_Ok;
3291 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3294 /*************************************************************
3295 * WineEngCreateFontInstance
3298 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3300 GdiFont *ret;
3301 Face *face, *best, *best_bitmap;
3302 Family *family, *last_resort_family;
3303 struct list *family_elem_ptr, *face_elem_ptr;
3304 INT height, width = 0;
3305 unsigned int score = 0, new_score;
3306 signed int diff = 0, newdiff;
3307 BOOL bd, it, can_use_bitmap;
3308 LOGFONTW lf;
3309 CHARSETINFO csi;
3310 HFONTLIST *hflist;
3311 FMAT2 dcmat;
3312 FontSubst *psub = NULL;
3314 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3315 lf.lfWidth = abs(lf.lfWidth);
3317 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3319 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3320 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3321 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3322 lf.lfEscapement);
3324 if(dc->GraphicsMode == GM_ADVANCED)
3325 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3326 else
3328 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3329 font scaling abilities. */
3330 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3331 dcmat.eM21 = dcmat.eM12 = 0;
3334 /* Try to avoid not necessary glyph transformations */
3335 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3337 lf.lfHeight *= fabs(dcmat.eM11);
3338 lf.lfWidth *= fabs(dcmat.eM11);
3339 dcmat.eM11 = dcmat.eM22 = 1.0;
3342 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3343 dcmat.eM21, dcmat.eM22);
3345 EnterCriticalSection( &freetype_cs );
3347 /* check the cache first */
3348 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3349 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3350 LeaveCriticalSection( &freetype_cs );
3351 return ret;
3354 TRACE("not in cache\n");
3355 if(list_empty(&font_list)) /* No fonts installed */
3357 TRACE("No fonts installed\n");
3358 LeaveCriticalSection( &freetype_cs );
3359 return NULL;
3361 if(!have_installed_roman_font)
3363 TRACE("No roman font installed\n");
3364 LeaveCriticalSection( &freetype_cs );
3365 return NULL;
3368 ret = alloc_font();
3370 ret->font_desc.matrix = dcmat;
3371 ret->font_desc.lf = lf;
3372 ret->font_desc.can_use_bitmap = can_use_bitmap;
3373 calc_hash(&ret->font_desc);
3374 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3375 hflist->hfont = hfont;
3376 list_add_head(&ret->hfontlist, &hflist->entry);
3378 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3379 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3380 original value lfCharSet. Note this is a special case for
3381 Symbol and doesn't happen at least for "Wingdings*" */
3383 if(!strcmpiW(lf.lfFaceName, SymbolW))
3384 lf.lfCharSet = SYMBOL_CHARSET;
3386 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3387 switch(lf.lfCharSet) {
3388 case DEFAULT_CHARSET:
3389 csi.fs.fsCsb[0] = 0;
3390 break;
3391 default:
3392 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3393 csi.fs.fsCsb[0] = 0;
3394 break;
3398 family = NULL;
3399 if(lf.lfFaceName[0] != '\0') {
3400 SYSTEM_LINKS *font_link;
3401 CHILD_FONT *font_link_entry;
3402 LPWSTR FaceName = lf.lfFaceName;
3405 * Check for a leading '@' this signals that the font is being
3406 * requested in tategaki mode (vertical writing substitution) but
3407 * does not affect the fontface that is to be selected.
3409 if (lf.lfFaceName[0]=='@')
3410 FaceName = &lf.lfFaceName[1];
3412 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3414 if(psub) {
3415 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3416 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3417 if (psub->to.charset != -1)
3418 lf.lfCharSet = psub->to.charset;
3421 /* We want a match on name and charset or just name if
3422 charset was DEFAULT_CHARSET. If the latter then
3423 we fixup the returned charset later in get_nearest_charset
3424 where we'll either use the charset of the current ansi codepage
3425 or if that's unavailable the first charset that the font supports.
3427 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3428 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3429 if (!strcmpiW(family->FamilyName, FaceName) ||
3430 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3432 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3433 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3434 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3435 if(face->scalable || can_use_bitmap)
3436 goto found;
3442 * Try check the SystemLink list first for a replacement font.
3443 * We may find good replacements there.
3445 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3447 if(!strcmpiW(font_link->font_name, FaceName) ||
3448 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3450 TRACE("found entry in system list\n");
3451 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3453 face = font_link_entry->face;
3454 family = face->family;
3455 if(csi.fs.fsCsb[0] &
3456 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3458 if(face->scalable || can_use_bitmap)
3459 goto found;
3466 psub = NULL; /* substitution is no more relevant */
3468 /* If requested charset was DEFAULT_CHARSET then try using charset
3469 corresponding to the current ansi codepage */
3470 if (!csi.fs.fsCsb[0])
3472 INT acp = GetACP();
3473 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3474 FIXME("TCI failed on codepage %d\n", acp);
3475 csi.fs.fsCsb[0] = 0;
3476 } else
3477 lf.lfCharSet = csi.ciCharset;
3480 /* Face families are in the top 4 bits of lfPitchAndFamily,
3481 so mask with 0xF0 before testing */
3483 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3484 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3485 strcpyW(lf.lfFaceName, defFixed);
3486 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3487 strcpyW(lf.lfFaceName, defSerif);
3488 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3489 strcpyW(lf.lfFaceName, defSans);
3490 else
3491 strcpyW(lf.lfFaceName, defSans);
3492 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3493 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3494 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3495 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3496 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3497 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3498 if(face->scalable || can_use_bitmap)
3499 goto found;
3504 last_resort_family = NULL;
3505 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3506 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3507 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3508 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3509 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3510 if(face->scalable)
3511 goto found;
3512 if(can_use_bitmap && !last_resort_family)
3513 last_resort_family = family;
3518 if(last_resort_family) {
3519 family = last_resort_family;
3520 csi.fs.fsCsb[0] = 0;
3521 goto found;
3524 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3525 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3526 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3527 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3528 if(face->scalable) {
3529 csi.fs.fsCsb[0] = 0;
3530 WARN("just using first face for now\n");
3531 goto found;
3533 if(can_use_bitmap && !last_resort_family)
3534 last_resort_family = family;
3537 if(!last_resort_family) {
3538 FIXME("can't find a single appropriate font - bailing\n");
3539 free_font(ret);
3540 LeaveCriticalSection( &freetype_cs );
3541 return NULL;
3544 WARN("could only find a bitmap font - this will probably look awful!\n");
3545 family = last_resort_family;
3546 csi.fs.fsCsb[0] = 0;
3548 found:
3549 it = lf.lfItalic ? 1 : 0;
3550 bd = lf.lfWeight > 550 ? 1 : 0;
3552 height = lf.lfHeight;
3554 face = best = best_bitmap = NULL;
3555 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3557 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3559 BOOL italic, bold;
3561 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3562 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3563 new_score = (italic ^ it) + (bold ^ bd);
3564 if(!best || new_score <= score)
3566 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3567 italic, bold, it, bd);
3568 score = new_score;
3569 best = face;
3570 if(best->scalable && score == 0) break;
3571 if(!best->scalable)
3573 if(height > 0)
3574 newdiff = height - (signed int)(best->size.height);
3575 else
3576 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3577 if(!best_bitmap || new_score < score ||
3578 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3580 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3581 diff = newdiff;
3582 best_bitmap = best;
3583 if(score == 0 && diff == 0) break;
3589 if(best)
3590 face = best->scalable ? best : best_bitmap;
3591 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3592 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3594 ret->fs = face->fs;
3596 if(csi.fs.fsCsb[0]) {
3597 ret->charset = lf.lfCharSet;
3598 ret->codepage = csi.ciACP;
3600 else
3601 ret->charset = get_nearest_charset(face, &ret->codepage);
3603 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3604 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3606 ret->aveWidth = height ? lf.lfWidth : 0;
3608 if(!face->scalable) {
3609 /* Windows uses integer scaling factors for bitmap fonts */
3610 INT scale, scaled_height;
3612 /* FIXME: rotation of bitmap fonts is ignored */
3613 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3614 if (ret->aveWidth)
3615 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3616 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3618 if (height != 0) height = diff;
3619 height += face->size.height;
3621 scale = (height + face->size.height - 1) / face->size.height;
3622 scaled_height = scale * face->size.height;
3623 /* XP allows not more than 10% deviation */
3624 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3625 ret->scale_y = scale;
3627 width = face->size.x_ppem >> 6;
3628 height = face->size.y_ppem >> 6;
3630 else
3631 ret->scale_y = 1.0;
3632 TRACE("font scale y: %f\n", ret->scale_y);
3634 ret->ft_face = OpenFontFace(ret, face, width, height);
3636 if (!ret->ft_face)
3638 free_font( ret );
3639 LeaveCriticalSection( &freetype_cs );
3640 return 0;
3643 ret->ntmFlags = face->ntmFlags;
3645 if (ret->charset == SYMBOL_CHARSET &&
3646 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3647 /* No ops */
3649 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3650 /* No ops */
3652 else {
3653 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3656 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3657 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3658 ret->underline = lf.lfUnderline ? 0xff : 0;
3659 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3660 create_child_font_list(ret);
3662 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3664 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3665 if (length != GDI_ERROR)
3667 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3668 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3669 TRACE("Loaded GSUB table of %i bytes\n",length);
3673 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3675 add_to_cache(ret);
3676 LeaveCriticalSection( &freetype_cs );
3677 return ret;
3680 static void dump_gdi_font_list(void)
3682 GdiFont *gdiFont;
3683 struct list *elem_ptr;
3685 TRACE("---------- gdiFont Cache ----------\n");
3686 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3687 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3688 TRACE("gdiFont=%p %s %d\n",
3689 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3692 TRACE("---------- Unused gdiFont Cache ----------\n");
3693 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3694 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3695 TRACE("gdiFont=%p %s %d\n",
3696 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3700 /*************************************************************
3701 * WineEngDestroyFontInstance
3703 * free the gdiFont associated with this handle
3706 BOOL WineEngDestroyFontInstance(HFONT handle)
3708 GdiFont *gdiFont;
3709 HFONTLIST *hflist;
3710 BOOL ret = FALSE;
3711 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3712 int i = 0;
3714 EnterCriticalSection( &freetype_cs );
3716 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3718 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3719 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3720 if(hflist->hfont == handle)
3722 TRACE("removing child font %p from child list\n", gdiFont);
3723 list_remove(&gdiFont->entry);
3724 LeaveCriticalSection( &freetype_cs );
3725 return TRUE;
3729 TRACE("destroying hfont=%p\n", handle);
3730 if(TRACE_ON(font))
3731 dump_gdi_font_list();
3733 font_elem_ptr = list_head(&gdi_font_list);
3734 while(font_elem_ptr) {
3735 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3736 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3738 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3739 while(hfontlist_elem_ptr) {
3740 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3741 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3742 if(hflist->hfont == handle) {
3743 list_remove(&hflist->entry);
3744 HeapFree(GetProcessHeap(), 0, hflist);
3745 ret = TRUE;
3748 if(list_empty(&gdiFont->hfontlist)) {
3749 TRACE("Moving to Unused list\n");
3750 list_remove(&gdiFont->entry);
3751 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3756 font_elem_ptr = list_head(&unused_gdi_font_list);
3757 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3758 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3759 while(font_elem_ptr) {
3760 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3761 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3762 TRACE("freeing %p\n", gdiFont);
3763 list_remove(&gdiFont->entry);
3764 free_font(gdiFont);
3766 LeaveCriticalSection( &freetype_cs );
3767 return ret;
3770 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3771 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3773 GdiFont *font;
3774 LONG width, height;
3776 if (face->cached_enum_data)
3778 TRACE("Cached\n");
3779 *pelf = face->cached_enum_data->elf;
3780 *pntm = face->cached_enum_data->ntm;
3781 *ptype = face->cached_enum_data->type;
3782 return;
3785 font = alloc_font();
3787 if(face->scalable) {
3788 height = -2048; /* 2048 is the most common em size */
3789 width = 0;
3790 } else {
3791 height = face->size.y_ppem >> 6;
3792 width = face->size.x_ppem >> 6;
3794 font->scale_y = 1.0;
3796 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3798 free_font(font);
3799 return;
3802 font->name = strdupW(face->family->FamilyName);
3803 font->ntmFlags = face->ntmFlags;
3805 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3807 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3809 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3811 lstrcpynW(pelf->elfLogFont.lfFaceName,
3812 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3813 LF_FACESIZE);
3814 lstrcpynW(pelf->elfFullName,
3815 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3816 LF_FULLFACESIZE);
3817 lstrcpynW(pelf->elfStyle,
3818 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3819 LF_FACESIZE);
3821 else
3823 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3825 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3827 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3828 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3829 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3832 pntm->ntmTm.ntmFlags = face->ntmFlags;
3833 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3834 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3835 pntm->ntmFontSig = face->fs;
3837 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3839 pelf->elfLogFont.lfEscapement = 0;
3840 pelf->elfLogFont.lfOrientation = 0;
3841 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3842 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3843 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3844 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3845 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3846 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3847 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3848 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3849 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3850 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3851 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3853 *ptype = 0;
3854 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3855 *ptype |= TRUETYPE_FONTTYPE;
3856 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3857 *ptype |= DEVICE_FONTTYPE;
3858 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3859 *ptype |= RASTER_FONTTYPE;
3861 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3862 if (face->cached_enum_data)
3864 face->cached_enum_data->elf = *pelf;
3865 face->cached_enum_data->ntm = *pntm;
3866 face->cached_enum_data->type = *ptype;
3869 free_font(font);
3872 /*************************************************************
3873 * WineEngEnumFonts
3876 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3878 Family *family;
3879 Face *face;
3880 struct list *family_elem_ptr, *face_elem_ptr;
3881 ENUMLOGFONTEXW elf;
3882 NEWTEXTMETRICEXW ntm;
3883 DWORD type;
3884 FONTSIGNATURE fs;
3885 CHARSETINFO csi;
3886 LOGFONTW lf;
3887 int i;
3889 if (!plf)
3891 lf.lfCharSet = DEFAULT_CHARSET;
3892 lf.lfPitchAndFamily = 0;
3893 lf.lfFaceName[0] = 0;
3894 plf = &lf;
3897 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3899 EnterCriticalSection( &freetype_cs );
3900 if(plf->lfFaceName[0]) {
3901 FontSubst *psub;
3902 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3904 if(psub) {
3905 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3906 debugstr_w(psub->to.name));
3907 lf = *plf;
3908 strcpyW(lf.lfFaceName, psub->to.name);
3909 plf = &lf;
3912 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3913 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3914 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3915 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3916 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3917 GetEnumStructs(face, &elf, &ntm, &type);
3918 for(i = 0; i < 32; i++) {
3919 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3920 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3921 strcpyW(elf.elfScript, OEM_DOSW);
3922 i = 32; /* break out of loop */
3923 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3924 continue;
3925 else {
3926 fs.fsCsb[0] = 1L << i;
3927 fs.fsCsb[1] = 0;
3928 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3929 TCI_SRCFONTSIG))
3930 csi.ciCharset = DEFAULT_CHARSET;
3931 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3932 if(csi.ciCharset != DEFAULT_CHARSET) {
3933 elf.elfLogFont.lfCharSet =
3934 ntm.ntmTm.tmCharSet = csi.ciCharset;
3935 if(ElfScriptsW[i])
3936 strcpyW(elf.elfScript, ElfScriptsW[i]);
3937 else
3938 FIXME("Unknown elfscript for bit %d\n", i);
3941 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3942 debugstr_w(elf.elfLogFont.lfFaceName),
3943 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3944 csi.ciCharset, type, debugstr_w(elf.elfScript),
3945 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3946 ntm.ntmTm.ntmFlags);
3947 /* release section before callback (FIXME) */
3948 LeaveCriticalSection( &freetype_cs );
3949 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3950 EnterCriticalSection( &freetype_cs );
3955 } else {
3956 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3957 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3958 face_elem_ptr = list_head(&family->faces);
3959 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3960 GetEnumStructs(face, &elf, &ntm, &type);
3961 for(i = 0; i < 32; i++) {
3962 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3963 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3964 strcpyW(elf.elfScript, OEM_DOSW);
3965 i = 32; /* break out of loop */
3966 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3967 continue;
3968 else {
3969 fs.fsCsb[0] = 1L << i;
3970 fs.fsCsb[1] = 0;
3971 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3972 TCI_SRCFONTSIG))
3973 csi.ciCharset = DEFAULT_CHARSET;
3974 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3975 if(csi.ciCharset != DEFAULT_CHARSET) {
3976 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3977 csi.ciCharset;
3978 if(ElfScriptsW[i])
3979 strcpyW(elf.elfScript, ElfScriptsW[i]);
3980 else
3981 FIXME("Unknown elfscript for bit %d\n", i);
3984 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3985 debugstr_w(elf.elfLogFont.lfFaceName),
3986 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3987 csi.ciCharset, type, debugstr_w(elf.elfScript),
3988 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3989 ntm.ntmTm.ntmFlags);
3990 /* release section before callback (FIXME) */
3991 LeaveCriticalSection( &freetype_cs );
3992 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3993 EnterCriticalSection( &freetype_cs );
3997 LeaveCriticalSection( &freetype_cs );
3998 return 1;
4001 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4003 pt->x.value = vec->x >> 6;
4004 pt->x.fract = (vec->x & 0x3f) << 10;
4005 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4006 pt->y.value = vec->y >> 6;
4007 pt->y.fract = (vec->y & 0x3f) << 10;
4008 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4009 return;
4012 /***************************************************
4013 * According to the MSDN documentation on WideCharToMultiByte,
4014 * certain codepages cannot set the default_used parameter.
4015 * This returns TRUE if the codepage can set that parameter, false else
4016 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4018 static BOOL codepage_sets_default_used(UINT codepage)
4020 switch (codepage)
4022 case CP_UTF7:
4023 case CP_UTF8:
4024 case CP_SYMBOL:
4025 return FALSE;
4026 default:
4027 return TRUE;
4032 * GSUB Table handling functions
4035 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4037 const GSUB_CoverageFormat1* cf1;
4039 cf1 = table;
4041 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4043 int count = GET_BE_WORD(cf1->GlyphCount);
4044 int i;
4045 TRACE("Coverage Format 1, %i glyphs\n",count);
4046 for (i = 0; i < count; i++)
4047 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4048 return i;
4049 return -1;
4051 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4053 const GSUB_CoverageFormat2* cf2;
4054 int i;
4055 int count;
4056 cf2 = (GSUB_CoverageFormat2*)cf1;
4058 count = GET_BE_WORD(cf2->RangeCount);
4059 TRACE("Coverage Format 2, %i ranges\n",count);
4060 for (i = 0; i < count; i++)
4062 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4063 return -1;
4064 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4065 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4067 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4068 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4071 return -1;
4073 else
4074 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4076 return -1;
4079 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4081 const GSUB_ScriptList *script;
4082 const GSUB_Script *deflt = NULL;
4083 int i;
4084 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4086 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4087 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4089 const GSUB_Script *scr;
4090 int offset;
4092 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4093 scr = (GSUB_Script*)((LPBYTE)script + offset);
4095 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4096 return scr;
4097 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4098 deflt = scr;
4100 return deflt;
4103 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4105 int i;
4106 int offset;
4107 const GSUB_LangSys *Lang;
4109 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4111 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4113 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4114 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4116 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4117 return Lang;
4119 offset = GET_BE_WORD(script->DefaultLangSys);
4120 if (offset)
4122 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4123 return Lang;
4125 return NULL;
4128 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4130 int i;
4131 const GSUB_FeatureList *feature;
4132 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4134 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4135 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4137 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4138 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4140 const GSUB_Feature *feat;
4141 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4142 return feat;
4145 return NULL;
4148 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4150 int i;
4151 int offset;
4152 const GSUB_LookupList *lookup;
4153 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4155 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4156 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4158 const GSUB_LookupTable *look;
4159 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4160 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4161 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4162 if (GET_BE_WORD(look->LookupType) != 1)
4163 FIXME("We only handle SubType 1\n");
4164 else
4166 int j;
4168 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4170 const GSUB_SingleSubstFormat1 *ssf1;
4171 offset = GET_BE_WORD(look->SubTable[j]);
4172 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4173 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4175 int offset = GET_BE_WORD(ssf1->Coverage);
4176 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4177 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4179 TRACE(" Glyph 0x%x ->",glyph);
4180 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4181 TRACE(" 0x%x\n",glyph);
4184 else
4186 const GSUB_SingleSubstFormat2 *ssf2;
4187 INT index;
4188 INT offset;
4190 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4191 offset = GET_BE_WORD(ssf1->Coverage);
4192 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4193 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4194 TRACE(" Coverage index %i\n",index);
4195 if (index != -1)
4197 TRACE(" Glyph is 0x%x ->",glyph);
4198 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4199 TRACE("0x%x\n",glyph);
4205 return glyph;
4208 static const char* get_opentype_script(const GdiFont *font)
4211 * I am not sure if this is the correct way to generate our script tag
4214 switch (font->charset)
4216 case ANSI_CHARSET: return "latn";
4217 case BALTIC_CHARSET: return "latn"; /* ?? */
4218 case CHINESEBIG5_CHARSET: return "hani";
4219 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4220 case GB2312_CHARSET: return "hani";
4221 case GREEK_CHARSET: return "grek";
4222 case HANGUL_CHARSET: return "hang";
4223 case RUSSIAN_CHARSET: return "cyrl";
4224 case SHIFTJIS_CHARSET: return "kana";
4225 case TURKISH_CHARSET: return "latn"; /* ?? */
4226 case VIETNAMESE_CHARSET: return "latn";
4227 case JOHAB_CHARSET: return "latn"; /* ?? */
4228 case ARABIC_CHARSET: return "arab";
4229 case HEBREW_CHARSET: return "hebr";
4230 case THAI_CHARSET: return "thai";
4231 default: return "latn";
4235 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4237 const GSUB_Header *header;
4238 const GSUB_Script *script;
4239 const GSUB_LangSys *language;
4240 const GSUB_Feature *feature;
4242 if (!font->GSUB_Table)
4243 return glyph;
4245 header = font->GSUB_Table;
4247 script = GSUB_get_script_table(header, get_opentype_script(font));
4248 if (!script)
4250 TRACE("Script not found\n");
4251 return glyph;
4253 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4254 if (!language)
4256 TRACE("Language not found\n");
4257 return glyph;
4259 feature = GSUB_get_feature(header, language, "vrt2");
4260 if (!feature)
4261 feature = GSUB_get_feature(header, language, "vert");
4262 if (!feature)
4264 TRACE("vrt2/vert feature not found\n");
4265 return glyph;
4267 return GSUB_apply_feature(header, feature, glyph);
4270 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4272 FT_UInt glyphId;
4274 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4275 WCHAR wc = (WCHAR)glyph;
4276 BOOL default_used;
4277 BOOL *default_used_pointer;
4278 FT_UInt ret;
4279 char buf;
4280 default_used_pointer = NULL;
4281 default_used = FALSE;
4282 if (codepage_sets_default_used(font->codepage))
4283 default_used_pointer = &default_used;
4284 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4285 ret = 0;
4286 else
4287 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4288 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4289 return get_GSUB_vert_glyph(font,ret);
4292 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4293 glyph = glyph + 0xf000;
4294 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4295 return get_GSUB_vert_glyph(font,glyphId);
4298 /*************************************************************
4299 * WineEngGetGlyphIndices
4302 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4303 LPWORD pgi, DWORD flags)
4305 int i;
4306 int default_char = -1;
4308 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4310 for(i = 0; i < count; i++)
4312 pgi[i] = get_glyph_index(font, lpstr[i]);
4313 if (pgi[i] == 0)
4315 if (default_char == -1)
4317 if (FT_IS_SFNT(font->ft_face))
4319 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4320 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4322 else
4324 TEXTMETRICW textm;
4325 WineEngGetTextMetrics(font, &textm);
4326 default_char = textm.tmDefaultChar;
4329 pgi[i] = default_char;
4332 return count;
4335 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4337 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4338 return !memcmp(matrix, &identity, sizeof(FMAT2));
4341 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4343 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4344 return !memcmp(matrix, &identity, sizeof(MAT2));
4347 /*************************************************************
4348 * WineEngGetGlyphOutline
4350 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4351 * except that the first parameter is the HWINEENGFONT of the font in
4352 * question rather than an HDC.
4355 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4356 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4357 const MAT2* lpmat)
4359 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4360 FT_Face ft_face = incoming_font->ft_face;
4361 GdiFont *font = incoming_font;
4362 FT_UInt glyph_index;
4363 DWORD width, height, pitch, needed = 0;
4364 FT_Bitmap ft_bitmap;
4365 FT_Error err;
4366 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4367 FT_Angle angle = 0;
4368 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4369 double widthRatio = 1.0;
4370 FT_Matrix transMat = identityMat;
4371 FT_Matrix transMatUnrotated;
4372 BOOL needsTransform = FALSE;
4373 BOOL tategaki = (font->GSUB_Table != NULL);
4374 UINT original_index;
4376 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4377 buflen, buf, lpmat);
4379 TRACE("font transform %f %f %f %f\n",
4380 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4381 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4383 EnterCriticalSection( &freetype_cs );
4385 if(format & GGO_GLYPH_INDEX) {
4386 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4387 original_index = glyph;
4388 format &= ~GGO_GLYPH_INDEX;
4389 } else {
4390 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4391 ft_face = font->ft_face;
4392 original_index = glyph_index;
4395 if(format & GGO_UNHINTED) {
4396 load_flags |= FT_LOAD_NO_HINTING;
4397 format &= ~GGO_UNHINTED;
4400 /* tategaki never appears to happen to lower glyph index */
4401 if (glyph_index < TATEGAKI_LOWER_BOUND )
4402 tategaki = FALSE;
4404 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4405 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4406 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4407 font->gmsize * sizeof(GM*));
4408 } else {
4409 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4410 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4412 *lpgm = FONT_GM(font,original_index)->gm;
4413 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4414 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4415 lpgm->gmCellIncX, lpgm->gmCellIncY);
4416 LeaveCriticalSection( &freetype_cs );
4417 return 1; /* FIXME */
4421 if (!font->gm[original_index / GM_BLOCK_SIZE])
4422 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4424 /* Scaling factor */
4425 if (font->aveWidth)
4427 TEXTMETRICW tm;
4429 WineEngGetTextMetrics(font, &tm);
4431 widthRatio = (double)font->aveWidth;
4432 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4434 else
4435 widthRatio = font->scale_y;
4437 /* Scaling transform */
4438 if (widthRatio != 1.0 || font->scale_y != 1.0)
4440 FT_Matrix scaleMat;
4441 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4442 scaleMat.xy = 0;
4443 scaleMat.yx = 0;
4444 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4446 pFT_Matrix_Multiply(&scaleMat, &transMat);
4447 needsTransform = TRUE;
4450 /* Slant transform */
4451 if (font->fake_italic) {
4452 FT_Matrix slantMat;
4454 slantMat.xx = (1 << 16);
4455 slantMat.xy = ((1 << 16) >> 2);
4456 slantMat.yx = 0;
4457 slantMat.yy = (1 << 16);
4458 pFT_Matrix_Multiply(&slantMat, &transMat);
4459 needsTransform = TRUE;
4462 /* Rotation transform */
4463 transMatUnrotated = transMat;
4464 if(font->orientation && !tategaki) {
4465 FT_Matrix rotationMat;
4466 FT_Vector vecAngle;
4467 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4468 pFT_Vector_Unit(&vecAngle, angle);
4469 rotationMat.xx = vecAngle.x;
4470 rotationMat.xy = -vecAngle.y;
4471 rotationMat.yx = -rotationMat.xy;
4472 rotationMat.yy = rotationMat.xx;
4474 pFT_Matrix_Multiply(&rotationMat, &transMat);
4475 needsTransform = TRUE;
4478 /* World transform */
4479 if (!is_identity_FMAT2(&font->font_desc.matrix))
4481 FT_Matrix worldMat;
4482 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4483 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4484 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4485 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4486 pFT_Matrix_Multiply(&worldMat, &transMat);
4487 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4488 needsTransform = TRUE;
4491 /* Extra transformation specified by caller */
4492 if (lpmat && !is_identity_MAT2(lpmat))
4494 FT_Matrix extraMat;
4495 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4496 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4497 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4498 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4499 pFT_Matrix_Multiply(&extraMat, &transMat);
4500 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4501 needsTransform = TRUE;
4504 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4505 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4506 format == GGO_GRAY8_BITMAP))
4508 load_flags |= FT_LOAD_NO_BITMAP;
4511 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4513 if(err) {
4514 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4515 LeaveCriticalSection( &freetype_cs );
4516 return GDI_ERROR;
4519 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4520 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4522 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4523 lsb = left >> 6;
4524 bbx = (right - left) >> 6;
4526 if(!needsTransform) {
4527 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4528 bottom = (ft_face->glyph->metrics.horiBearingY -
4529 ft_face->glyph->metrics.height) & -64;
4530 lpgm->gmCellIncX = adv;
4531 lpgm->gmCellIncY = 0;
4532 } else {
4533 INT xc, yc;
4534 FT_Vector vec;
4535 for(xc = 0; xc < 2; xc++) {
4536 for(yc = 0; yc < 2; yc++) {
4537 vec.x = (ft_face->glyph->metrics.horiBearingX +
4538 xc * ft_face->glyph->metrics.width);
4539 vec.y = ft_face->glyph->metrics.horiBearingY -
4540 yc * ft_face->glyph->metrics.height;
4541 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4542 pFT_Vector_Transform(&vec, &transMat);
4543 if(xc == 0 && yc == 0) {
4544 left = right = vec.x;
4545 top = bottom = vec.y;
4546 } else {
4547 if(vec.x < left) left = vec.x;
4548 else if(vec.x > right) right = vec.x;
4549 if(vec.y < bottom) bottom = vec.y;
4550 else if(vec.y > top) top = vec.y;
4554 left = left & -64;
4555 right = (right + 63) & -64;
4556 bottom = bottom & -64;
4557 top = (top + 63) & -64;
4559 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4560 vec.x = ft_face->glyph->metrics.horiAdvance;
4561 vec.y = 0;
4562 pFT_Vector_Transform(&vec, &transMat);
4563 lpgm->gmCellIncX = (vec.x+63) >> 6;
4564 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4566 vec.x = ft_face->glyph->metrics.horiAdvance;
4567 vec.y = 0;
4568 pFT_Vector_Transform(&vec, &transMatUnrotated);
4569 adv = (vec.x+63) >> 6;
4571 lpgm->gmBlackBoxX = (right - left) >> 6;
4572 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4573 lpgm->gmptGlyphOrigin.x = left >> 6;
4574 lpgm->gmptGlyphOrigin.y = top >> 6;
4576 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4577 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4578 lpgm->gmCellIncX, lpgm->gmCellIncY);
4580 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4581 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4583 FONT_GM(font,original_index)->gm = *lpgm;
4584 FONT_GM(font,original_index)->adv = adv;
4585 FONT_GM(font,original_index)->lsb = lsb;
4586 FONT_GM(font,original_index)->bbx = bbx;
4587 FONT_GM(font,original_index)->init = TRUE;
4590 if(format == GGO_METRICS)
4592 LeaveCriticalSection( &freetype_cs );
4593 return 1; /* FIXME */
4596 if(ft_face->glyph->format != ft_glyph_format_outline &&
4597 (needsTransform || format == GGO_NATIVE || format == GGO_BEZIER ||
4598 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4599 format == GGO_GRAY8_BITMAP))
4601 TRACE("loaded a bitmap\n");
4602 LeaveCriticalSection( &freetype_cs );
4603 return GDI_ERROR;
4606 switch(format) {
4607 case GGO_BITMAP:
4608 width = lpgm->gmBlackBoxX;
4609 height = lpgm->gmBlackBoxY;
4610 pitch = ((width + 31) >> 5) << 2;
4611 needed = pitch * height;
4613 if(!buf || !buflen) break;
4615 switch(ft_face->glyph->format) {
4616 case ft_glyph_format_bitmap:
4618 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4619 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4620 INT h = ft_face->glyph->bitmap.rows;
4621 while(h--) {
4622 memcpy(dst, src, w);
4623 src += ft_face->glyph->bitmap.pitch;
4624 dst += pitch;
4626 break;
4629 case ft_glyph_format_outline:
4630 ft_bitmap.width = width;
4631 ft_bitmap.rows = height;
4632 ft_bitmap.pitch = pitch;
4633 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4634 ft_bitmap.buffer = buf;
4636 if(needsTransform)
4637 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4639 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4641 /* Note: FreeType will only set 'black' bits for us. */
4642 memset(buf, 0, needed);
4643 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4644 break;
4646 default:
4647 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4648 LeaveCriticalSection( &freetype_cs );
4649 return GDI_ERROR;
4651 break;
4653 case GGO_GRAY2_BITMAP:
4654 case GGO_GRAY4_BITMAP:
4655 case GGO_GRAY8_BITMAP:
4656 case WINE_GGO_GRAY16_BITMAP:
4658 unsigned int mult, row, col;
4659 BYTE *start, *ptr;
4661 width = lpgm->gmBlackBoxX;
4662 height = lpgm->gmBlackBoxY;
4663 pitch = (width + 3) / 4 * 4;
4664 needed = pitch * height;
4666 if(!buf || !buflen) break;
4668 switch(ft_face->glyph->format) {
4669 case ft_glyph_format_bitmap:
4671 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4672 INT h = ft_face->glyph->bitmap.rows;
4673 INT x;
4674 while(h--) {
4675 for(x = 0; x < pitch; x++)
4677 if(x < ft_face->glyph->bitmap.width)
4678 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4679 else
4680 dst[x] = 0;
4682 src += ft_face->glyph->bitmap.pitch;
4683 dst += pitch;
4685 LeaveCriticalSection( &freetype_cs );
4686 return needed;
4688 case ft_glyph_format_outline:
4690 ft_bitmap.width = width;
4691 ft_bitmap.rows = height;
4692 ft_bitmap.pitch = pitch;
4693 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4694 ft_bitmap.buffer = buf;
4696 if(needsTransform)
4697 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4699 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4701 memset(ft_bitmap.buffer, 0, buflen);
4703 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4705 if(format == GGO_GRAY2_BITMAP)
4706 mult = 4;
4707 else if(format == GGO_GRAY4_BITMAP)
4708 mult = 16;
4709 else if(format == GGO_GRAY8_BITMAP)
4710 mult = 64;
4711 else /* format == WINE_GGO_GRAY16_BITMAP */
4713 LeaveCriticalSection( &freetype_cs );
4714 return needed;
4716 break;
4718 default:
4719 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4720 LeaveCriticalSection( &freetype_cs );
4721 return GDI_ERROR;
4724 start = buf;
4725 for(row = 0; row < height; row++) {
4726 ptr = start;
4727 for(col = 0; col < width; col++, ptr++) {
4728 *ptr = (((int)*ptr) * mult + 128) / 256;
4730 start += pitch;
4732 break;
4735 case WINE_GGO_HRGB_BITMAP:
4736 case WINE_GGO_HBGR_BITMAP:
4737 case WINE_GGO_VRGB_BITMAP:
4738 case WINE_GGO_VBGR_BITMAP:
4739 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4741 switch (ft_face->glyph->format)
4743 case FT_GLYPH_FORMAT_BITMAP:
4745 BYTE *src, *dst;
4746 INT src_pitch, x;
4748 width = lpgm->gmBlackBoxX;
4749 height = lpgm->gmBlackBoxY;
4750 pitch = width * 4;
4751 needed = pitch * height;
4753 if (!buf || !buflen) break;
4755 memset(buf, 0, buflen);
4756 dst = buf;
4757 src = ft_face->glyph->bitmap.buffer;
4758 src_pitch = ft_face->glyph->bitmap.pitch;
4760 while ( height-- )
4762 for (x = 0; x < width; x++)
4764 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4765 ((unsigned int *)dst)[x] = ~0u;
4767 src += src_pitch;
4768 dst += pitch;
4771 break;
4774 case FT_GLYPH_FORMAT_OUTLINE:
4776 unsigned int *dst;
4777 BYTE *src;
4778 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4779 INT x_shift, y_shift;
4780 BOOL rgb;
4781 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4782 FT_Render_Mode render_mode =
4783 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4784 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4786 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4788 if ( render_mode == FT_RENDER_MODE_LCD)
4790 lpgm->gmBlackBoxX += 2;
4791 lpgm->gmptGlyphOrigin.x -= 1;
4793 else
4795 lpgm->gmBlackBoxY += 2;
4796 lpgm->gmptGlyphOrigin.y += 1;
4800 width = lpgm->gmBlackBoxX;
4801 height = lpgm->gmBlackBoxY;
4802 pitch = width * 4;
4803 needed = pitch * height;
4805 if (!buf || !buflen) break;
4807 memset(buf, 0, buflen);
4808 dst = buf;
4809 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
4811 if ( needsTransform )
4812 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
4814 if ( pFT_Library_SetLcdFilter )
4815 pFT_Library_SetLcdFilter( library, lcdfilter );
4816 pFT_Render_Glyph (ft_face->glyph, render_mode);
4818 src = ft_face->glyph->bitmap.buffer;
4819 src_pitch = ft_face->glyph->bitmap.pitch;
4820 src_width = ft_face->glyph->bitmap.width;
4821 src_height = ft_face->glyph->bitmap.rows;
4823 if ( render_mode == FT_RENDER_MODE_LCD)
4825 rgb_interval = 1;
4826 hmul = 3;
4827 vmul = 1;
4829 else
4831 rgb_interval = src_pitch;
4832 hmul = 1;
4833 vmul = 3;
4836 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
4837 if ( x_shift < 0 ) x_shift = 0;
4838 if ( x_shift + (src_width / hmul) > width )
4839 x_shift = width - (src_width / hmul);
4841 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
4842 if ( y_shift < 0 ) y_shift = 0;
4843 if ( y_shift + (src_height / vmul) > height )
4844 y_shift = height - (src_height / vmul);
4846 dst += x_shift + y_shift * ( pitch / 4 );
4847 while ( src_height )
4849 for ( x = 0; x < src_width / hmul; x++ )
4851 if ( rgb )
4853 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
4854 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4855 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
4856 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4858 else
4860 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
4861 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4862 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
4863 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4866 src += src_pitch * vmul;
4867 dst += pitch / 4;
4868 src_height -= vmul;
4871 break;
4874 default:
4875 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
4876 LeaveCriticalSection ( &freetype_cs );
4877 return GDI_ERROR;
4880 break;
4882 #else
4883 LeaveCriticalSection( &freetype_cs );
4884 return GDI_ERROR;
4885 #endif
4887 case GGO_NATIVE:
4889 int contour, point = 0, first_pt;
4890 FT_Outline *outline = &ft_face->glyph->outline;
4891 TTPOLYGONHEADER *pph;
4892 TTPOLYCURVE *ppc;
4893 DWORD pph_start, cpfx, type;
4895 if(buflen == 0) buf = NULL;
4897 if (needsTransform && buf) {
4898 pFT_Outline_Transform(outline, &transMat);
4901 for(contour = 0; contour < outline->n_contours; contour++) {
4902 pph_start = needed;
4903 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4904 first_pt = point;
4905 if(buf) {
4906 pph->dwType = TT_POLYGON_TYPE;
4907 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4909 needed += sizeof(*pph);
4910 point++;
4911 while(point <= outline->contours[contour]) {
4912 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4913 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4914 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4915 cpfx = 0;
4916 do {
4917 if(buf)
4918 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4919 cpfx++;
4920 point++;
4921 } while(point <= outline->contours[contour] &&
4922 (outline->tags[point] & FT_Curve_Tag_On) ==
4923 (outline->tags[point-1] & FT_Curve_Tag_On));
4924 /* At the end of a contour Windows adds the start point, but
4925 only for Beziers */
4926 if(point > outline->contours[contour] &&
4927 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4928 if(buf)
4929 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4930 cpfx++;
4931 } else if(point <= outline->contours[contour] &&
4932 outline->tags[point] & FT_Curve_Tag_On) {
4933 /* add closing pt for bezier */
4934 if(buf)
4935 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4936 cpfx++;
4937 point++;
4939 if(buf) {
4940 ppc->wType = type;
4941 ppc->cpfx = cpfx;
4943 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4945 if(buf)
4946 pph->cb = needed - pph_start;
4948 break;
4950 case GGO_BEZIER:
4952 /* Convert the quadratic Beziers to cubic Beziers.
4953 The parametric eqn for a cubic Bezier is, from PLRM:
4954 r(t) = at^3 + bt^2 + ct + r0
4955 with the control points:
4956 r1 = r0 + c/3
4957 r2 = r1 + (c + b)/3
4958 r3 = r0 + c + b + a
4960 A quadratic Beizer has the form:
4961 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4963 So equating powers of t leads to:
4964 r1 = 2/3 p1 + 1/3 p0
4965 r2 = 2/3 p1 + 1/3 p2
4966 and of course r0 = p0, r3 = p2
4969 int contour, point = 0, first_pt;
4970 FT_Outline *outline = &ft_face->glyph->outline;
4971 TTPOLYGONHEADER *pph;
4972 TTPOLYCURVE *ppc;
4973 DWORD pph_start, cpfx, type;
4974 FT_Vector cubic_control[4];
4975 if(buflen == 0) buf = NULL;
4977 if (needsTransform && buf) {
4978 pFT_Outline_Transform(outline, &transMat);
4981 for(contour = 0; contour < outline->n_contours; contour++) {
4982 pph_start = needed;
4983 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4984 first_pt = point;
4985 if(buf) {
4986 pph->dwType = TT_POLYGON_TYPE;
4987 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4989 needed += sizeof(*pph);
4990 point++;
4991 while(point <= outline->contours[contour]) {
4992 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4993 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4994 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4995 cpfx = 0;
4996 do {
4997 if(type == TT_PRIM_LINE) {
4998 if(buf)
4999 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5000 cpfx++;
5001 point++;
5002 } else {
5003 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5004 so cpfx = 3n */
5006 /* FIXME: Possible optimization in endpoint calculation
5007 if there are two consecutive curves */
5008 cubic_control[0] = outline->points[point-1];
5009 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5010 cubic_control[0].x += outline->points[point].x + 1;
5011 cubic_control[0].y += outline->points[point].y + 1;
5012 cubic_control[0].x >>= 1;
5013 cubic_control[0].y >>= 1;
5015 if(point+1 > outline->contours[contour])
5016 cubic_control[3] = outline->points[first_pt];
5017 else {
5018 cubic_control[3] = outline->points[point+1];
5019 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5020 cubic_control[3].x += outline->points[point].x + 1;
5021 cubic_control[3].y += outline->points[point].y + 1;
5022 cubic_control[3].x >>= 1;
5023 cubic_control[3].y >>= 1;
5026 /* r1 = 1/3 p0 + 2/3 p1
5027 r2 = 1/3 p2 + 2/3 p1 */
5028 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5029 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5030 cubic_control[2] = cubic_control[1];
5031 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5032 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5033 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5034 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5035 if(buf) {
5036 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5037 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5038 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5040 cpfx += 3;
5041 point++;
5043 } while(point <= outline->contours[contour] &&
5044 (outline->tags[point] & FT_Curve_Tag_On) ==
5045 (outline->tags[point-1] & FT_Curve_Tag_On));
5046 /* At the end of a contour Windows adds the start point,
5047 but only for Beziers and we've already done that.
5049 if(point <= outline->contours[contour] &&
5050 outline->tags[point] & FT_Curve_Tag_On) {
5051 /* This is the closing pt of a bezier, but we've already
5052 added it, so just inc point and carry on */
5053 point++;
5055 if(buf) {
5056 ppc->wType = type;
5057 ppc->cpfx = cpfx;
5059 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5061 if(buf)
5062 pph->cb = needed - pph_start;
5064 break;
5067 default:
5068 FIXME("Unsupported format %d\n", format);
5069 LeaveCriticalSection( &freetype_cs );
5070 return GDI_ERROR;
5072 LeaveCriticalSection( &freetype_cs );
5073 return needed;
5076 static BOOL get_bitmap_text_metrics(GdiFont *font)
5078 FT_Face ft_face = font->ft_face;
5079 #ifdef HAVE_FREETYPE_FTWINFNT_H
5080 FT_WinFNT_HeaderRec winfnt_header;
5081 #endif
5082 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5083 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5084 font->potm->otmSize = size;
5086 #define TM font->potm->otmTextMetrics
5087 #ifdef HAVE_FREETYPE_FTWINFNT_H
5088 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5090 TM.tmHeight = winfnt_header.pixel_height;
5091 TM.tmAscent = winfnt_header.ascent;
5092 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5093 TM.tmInternalLeading = winfnt_header.internal_leading;
5094 TM.tmExternalLeading = winfnt_header.external_leading;
5095 TM.tmAveCharWidth = winfnt_header.avg_width;
5096 TM.tmMaxCharWidth = winfnt_header.max_width;
5097 TM.tmWeight = winfnt_header.weight;
5098 TM.tmOverhang = 0;
5099 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5100 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5101 TM.tmFirstChar = winfnt_header.first_char;
5102 TM.tmLastChar = winfnt_header.last_char;
5103 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5104 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5105 TM.tmItalic = winfnt_header.italic;
5106 TM.tmUnderlined = font->underline;
5107 TM.tmStruckOut = font->strikeout;
5108 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5109 TM.tmCharSet = winfnt_header.charset;
5111 else
5112 #endif
5114 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5115 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5116 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5117 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5118 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5119 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5120 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5121 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5122 TM.tmOverhang = 0;
5123 TM.tmDigitizedAspectX = 96; /* FIXME */
5124 TM.tmDigitizedAspectY = 96; /* FIXME */
5125 TM.tmFirstChar = 1;
5126 TM.tmLastChar = 255;
5127 TM.tmDefaultChar = 32;
5128 TM.tmBreakChar = 32;
5129 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5130 TM.tmUnderlined = font->underline;
5131 TM.tmStruckOut = font->strikeout;
5132 /* NB inverted meaning of TMPF_FIXED_PITCH */
5133 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5134 TM.tmCharSet = font->charset;
5136 #undef TM
5138 return TRUE;
5142 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5144 double scale_x, scale_y;
5146 if (font->aveWidth)
5148 scale_x = (double)font->aveWidth;
5149 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5151 else
5152 scale_x = font->scale_y;
5154 scale_x *= fabs(font->font_desc.matrix.eM11);
5155 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5157 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5158 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5160 SCALE_Y(ptm->tmHeight);
5161 SCALE_Y(ptm->tmAscent);
5162 SCALE_Y(ptm->tmDescent);
5163 SCALE_Y(ptm->tmInternalLeading);
5164 SCALE_Y(ptm->tmExternalLeading);
5165 SCALE_Y(ptm->tmOverhang);
5167 SCALE_X(ptm->tmAveCharWidth);
5168 SCALE_X(ptm->tmMaxCharWidth);
5170 #undef SCALE_X
5171 #undef SCALE_Y
5174 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5176 double scale_x, scale_y;
5178 if (font->aveWidth)
5180 scale_x = (double)font->aveWidth;
5181 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5183 else
5184 scale_x = font->scale_y;
5186 scale_x *= fabs(font->font_desc.matrix.eM11);
5187 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5189 scale_font_metrics(font, &potm->otmTextMetrics);
5191 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5192 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5194 SCALE_Y(potm->otmAscent);
5195 SCALE_Y(potm->otmDescent);
5196 SCALE_Y(potm->otmLineGap);
5197 SCALE_Y(potm->otmsCapEmHeight);
5198 SCALE_Y(potm->otmsXHeight);
5199 SCALE_Y(potm->otmrcFontBox.top);
5200 SCALE_Y(potm->otmrcFontBox.bottom);
5201 SCALE_X(potm->otmrcFontBox.left);
5202 SCALE_X(potm->otmrcFontBox.right);
5203 SCALE_Y(potm->otmMacAscent);
5204 SCALE_Y(potm->otmMacDescent);
5205 SCALE_Y(potm->otmMacLineGap);
5206 SCALE_X(potm->otmptSubscriptSize.x);
5207 SCALE_Y(potm->otmptSubscriptSize.y);
5208 SCALE_X(potm->otmptSubscriptOffset.x);
5209 SCALE_Y(potm->otmptSubscriptOffset.y);
5210 SCALE_X(potm->otmptSuperscriptSize.x);
5211 SCALE_Y(potm->otmptSuperscriptSize.y);
5212 SCALE_X(potm->otmptSuperscriptOffset.x);
5213 SCALE_Y(potm->otmptSuperscriptOffset.y);
5214 SCALE_Y(potm->otmsStrikeoutSize);
5215 SCALE_Y(potm->otmsStrikeoutPosition);
5216 SCALE_Y(potm->otmsUnderscoreSize);
5217 SCALE_Y(potm->otmsUnderscorePosition);
5219 #undef SCALE_X
5220 #undef SCALE_Y
5223 /*************************************************************
5224 * WineEngGetTextMetrics
5227 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5229 EnterCriticalSection( &freetype_cs );
5230 if(!font->potm) {
5231 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5232 if(!get_bitmap_text_metrics(font))
5234 LeaveCriticalSection( &freetype_cs );
5235 return FALSE;
5238 if(!font->potm)
5240 LeaveCriticalSection( &freetype_cs );
5241 return FALSE;
5243 *ptm = font->potm->otmTextMetrics;
5244 scale_font_metrics(font, ptm);
5245 LeaveCriticalSection( &freetype_cs );
5246 return TRUE;
5250 /*************************************************************
5251 * WineEngGetOutlineTextMetrics
5254 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5255 OUTLINETEXTMETRICW *potm)
5257 FT_Face ft_face = font->ft_face;
5258 UINT needed, lenfam, lensty, ret;
5259 TT_OS2 *pOS2;
5260 TT_HoriHeader *pHori;
5261 TT_Postscript *pPost;
5262 FT_Fixed x_scale, y_scale;
5263 WCHAR *family_nameW, *style_nameW;
5264 static const WCHAR spaceW[] = {' ', '\0'};
5265 char *cp;
5266 INT ascent, descent;
5268 TRACE("font=%p\n", font);
5270 if(!FT_IS_SCALABLE(ft_face))
5271 return 0;
5273 EnterCriticalSection( &freetype_cs );
5275 if(font->potm) {
5276 if(cbSize >= font->potm->otmSize)
5278 memcpy(potm, font->potm, font->potm->otmSize);
5279 scale_outline_font_metrics(font, potm);
5281 LeaveCriticalSection( &freetype_cs );
5282 return font->potm->otmSize;
5286 needed = sizeof(*potm);
5288 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5289 family_nameW = strdupW(font->name);
5291 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5292 * sizeof(WCHAR);
5293 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5294 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5295 style_nameW, lensty/sizeof(WCHAR));
5297 /* These names should be read from the TT name table */
5299 /* length of otmpFamilyName */
5300 needed += lenfam;
5302 /* length of otmpFaceName */
5303 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5304 needed += lenfam; /* just the family name */
5305 } else {
5306 needed += lenfam + lensty; /* family + " " + style */
5309 /* length of otmpStyleName */
5310 needed += lensty;
5312 /* length of otmpFullName */
5313 needed += lenfam + lensty;
5316 x_scale = ft_face->size->metrics.x_scale;
5317 y_scale = ft_face->size->metrics.y_scale;
5319 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5320 if(!pOS2) {
5321 FIXME("Can't find OS/2 table - not TT font?\n");
5322 ret = 0;
5323 goto end;
5326 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5327 if(!pHori) {
5328 FIXME("Can't find HHEA table - not TT font?\n");
5329 ret = 0;
5330 goto end;
5333 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5335 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",
5336 pOS2->usWinAscent, pOS2->usWinDescent,
5337 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5338 ft_face->ascender, ft_face->descender, ft_face->height,
5339 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5340 ft_face->bbox.yMax, ft_face->bbox.yMin);
5342 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5343 font->potm->otmSize = needed;
5345 #define TM font->potm->otmTextMetrics
5347 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5348 ascent = pHori->Ascender;
5349 descent = -pHori->Descender;
5350 } else {
5351 ascent = pOS2->usWinAscent;
5352 descent = pOS2->usWinDescent;
5355 if(font->yMax) {
5356 TM.tmAscent = font->yMax;
5357 TM.tmDescent = -font->yMin;
5358 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5359 } else {
5360 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5361 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5362 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5363 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5366 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5368 /* MSDN says:
5369 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5371 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5372 ((ascent + descent) -
5373 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5375 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5376 if (TM.tmAveCharWidth == 0) {
5377 TM.tmAveCharWidth = 1;
5379 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5380 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5381 TM.tmOverhang = 0;
5382 TM.tmDigitizedAspectX = 300;
5383 TM.tmDigitizedAspectY = 300;
5384 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5385 * symbol range to 0 - f0ff
5387 if (font->charset == SYMBOL_CHARSET)
5389 TM.tmFirstChar = 0;
5390 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5392 else
5394 TM.tmFirstChar = pOS2->usFirstCharIndex;
5395 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5397 TM.tmLastChar = pOS2->usLastCharIndex;
5398 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5399 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5400 TM.tmUnderlined = font->underline;
5401 TM.tmStruckOut = font->strikeout;
5403 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5404 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5405 (pOS2->version == 0xFFFFU ||
5406 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5407 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5408 else
5409 TM.tmPitchAndFamily = 0;
5411 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5412 case PAN_FAMILY_SCRIPT:
5413 TM.tmPitchAndFamily |= FF_SCRIPT;
5414 break;
5415 case PAN_FAMILY_DECORATIVE:
5416 case PAN_FAMILY_PICTORIAL:
5417 TM.tmPitchAndFamily |= FF_DECORATIVE;
5418 break;
5419 case PAN_FAMILY_TEXT_DISPLAY:
5420 if(TM.tmPitchAndFamily == 0) /* fixed */
5421 TM.tmPitchAndFamily = FF_MODERN;
5422 else {
5423 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5424 case PAN_SERIF_NORMAL_SANS:
5425 case PAN_SERIF_OBTUSE_SANS:
5426 case PAN_SERIF_PERP_SANS:
5427 TM.tmPitchAndFamily |= FF_SWISS;
5428 break;
5429 default:
5430 TM.tmPitchAndFamily |= FF_ROMAN;
5433 break;
5434 default:
5435 TM.tmPitchAndFamily |= FF_DONTCARE;
5438 if(FT_IS_SCALABLE(ft_face))
5439 TM.tmPitchAndFamily |= TMPF_VECTOR;
5441 if(FT_IS_SFNT(ft_face))
5443 if (font->ntmFlags & NTM_PS_OPENTYPE)
5444 TM.tmPitchAndFamily |= TMPF_DEVICE;
5445 else
5446 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5449 TM.tmCharSet = font->charset;
5451 font->potm->otmFiller = 0;
5452 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5453 font->potm->otmfsSelection = pOS2->fsSelection;
5454 font->potm->otmfsType = pOS2->fsType;
5455 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5456 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5457 font->potm->otmItalicAngle = 0; /* POST table */
5458 font->potm->otmEMSquare = ft_face->units_per_EM;
5459 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5460 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5461 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5462 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5463 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5464 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5465 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5466 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5467 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5468 font->potm->otmMacAscent = TM.tmAscent;
5469 font->potm->otmMacDescent = -TM.tmDescent;
5470 font->potm->otmMacLineGap = font->potm->otmLineGap;
5471 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5472 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5473 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5474 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5475 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5476 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5477 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5478 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5479 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5480 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5481 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5482 if(!pPost) {
5483 font->potm->otmsUnderscoreSize = 0;
5484 font->potm->otmsUnderscorePosition = 0;
5485 } else {
5486 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5487 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5489 #undef TM
5491 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5492 cp = (char*)font->potm + sizeof(*font->potm);
5493 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5494 strcpyW((WCHAR*)cp, family_nameW);
5495 cp += lenfam;
5496 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5497 strcpyW((WCHAR*)cp, style_nameW);
5498 cp += lensty;
5499 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5500 strcpyW((WCHAR*)cp, family_nameW);
5501 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5502 strcatW((WCHAR*)cp, spaceW);
5503 strcatW((WCHAR*)cp, style_nameW);
5504 cp += lenfam + lensty;
5505 } else
5506 cp += lenfam;
5507 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5508 strcpyW((WCHAR*)cp, family_nameW);
5509 strcatW((WCHAR*)cp, spaceW);
5510 strcatW((WCHAR*)cp, style_nameW);
5511 ret = needed;
5513 if(potm && needed <= cbSize)
5515 memcpy(potm, font->potm, font->potm->otmSize);
5516 scale_outline_font_metrics(font, potm);
5519 end:
5520 HeapFree(GetProcessHeap(), 0, style_nameW);
5521 HeapFree(GetProcessHeap(), 0, family_nameW);
5523 LeaveCriticalSection( &freetype_cs );
5524 return ret;
5527 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5529 HFONTLIST *hfontlist;
5530 child->font = alloc_font();
5531 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5532 if(!child->font->ft_face)
5534 free_font(child->font);
5535 child->font = NULL;
5536 return FALSE;
5539 child->font->font_desc = font->font_desc;
5540 child->font->ntmFlags = child->face->ntmFlags;
5541 child->font->orientation = font->orientation;
5542 child->font->scale_y = font->scale_y;
5543 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5544 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5545 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5546 child->font->base_font = font;
5547 list_add_head(&child_font_list, &child->font->entry);
5548 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5549 return TRUE;
5552 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5554 FT_UInt g;
5555 CHILD_FONT *child_font;
5557 if(font->base_font)
5558 font = font->base_font;
5560 *linked_font = font;
5562 if((*glyph = get_glyph_index(font, c)))
5563 return TRUE;
5565 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5567 if(!child_font->font)
5568 if(!load_child_font(font, child_font))
5569 continue;
5571 if(!child_font->font->ft_face)
5572 continue;
5573 g = get_glyph_index(child_font->font, c);
5574 if(g)
5576 *glyph = g;
5577 *linked_font = child_font->font;
5578 return TRUE;
5581 return FALSE;
5584 /*************************************************************
5585 * WineEngGetCharWidth
5588 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5589 LPINT buffer)
5591 UINT c;
5592 GLYPHMETRICS gm;
5593 FT_UInt glyph_index;
5594 GdiFont *linked_font;
5596 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5598 EnterCriticalSection( &freetype_cs );
5599 for(c = firstChar; c <= lastChar; c++) {
5600 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5601 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5602 &gm, 0, NULL, NULL);
5603 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5605 LeaveCriticalSection( &freetype_cs );
5606 return TRUE;
5609 /*************************************************************
5610 * WineEngGetCharABCWidths
5613 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5614 LPABC buffer)
5616 UINT c;
5617 GLYPHMETRICS gm;
5618 FT_UInt glyph_index;
5619 GdiFont *linked_font;
5621 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5623 if(!FT_IS_SCALABLE(font->ft_face))
5624 return FALSE;
5626 EnterCriticalSection( &freetype_cs );
5628 for(c = firstChar; c <= lastChar; c++) {
5629 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5630 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5631 &gm, 0, NULL, NULL);
5632 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5633 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5634 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5635 FONT_GM(linked_font,glyph_index)->bbx;
5637 LeaveCriticalSection( &freetype_cs );
5638 return TRUE;
5641 /*************************************************************
5642 * WineEngGetCharABCWidthsI
5645 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5646 LPABC buffer)
5648 UINT c;
5649 GLYPHMETRICS gm;
5650 FT_UInt glyph_index;
5651 GdiFont *linked_font;
5653 if(!FT_HAS_HORIZONTAL(font->ft_face))
5654 return FALSE;
5656 EnterCriticalSection( &freetype_cs );
5658 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5659 if (!pgi)
5660 for(c = firstChar; c < firstChar+count; c++) {
5661 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5662 &gm, 0, NULL, NULL);
5663 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5664 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5665 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5666 - FONT_GM(linked_font,c)->bbx;
5668 else
5669 for(c = 0; c < count; c++) {
5670 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5671 &gm, 0, NULL, NULL);
5672 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5673 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5674 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5675 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5678 LeaveCriticalSection( &freetype_cs );
5679 return TRUE;
5682 /*************************************************************
5683 * WineEngGetTextExtentExPoint
5686 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5687 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5689 INT idx;
5690 INT nfit = 0, ext;
5691 GLYPHMETRICS gm;
5692 TEXTMETRICW tm;
5693 FT_UInt glyph_index;
5694 GdiFont *linked_font;
5696 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5697 max_ext, size);
5699 EnterCriticalSection( &freetype_cs );
5701 size->cx = 0;
5702 WineEngGetTextMetrics(font, &tm);
5703 size->cy = tm.tmHeight;
5705 for(idx = 0; idx < count; idx++) {
5706 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5707 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5708 &gm, 0, NULL, NULL);
5709 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5710 ext = size->cx;
5711 if (! pnfit || ext <= max_ext) {
5712 ++nfit;
5713 if (dxs)
5714 dxs[idx] = ext;
5718 if (pnfit)
5719 *pnfit = nfit;
5721 LeaveCriticalSection( &freetype_cs );
5722 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5723 return TRUE;
5726 /*************************************************************
5727 * WineEngGetTextExtentExPointI
5730 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5731 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5733 INT idx;
5734 INT nfit = 0, ext;
5735 GLYPHMETRICS gm;
5736 TEXTMETRICW tm;
5738 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5740 EnterCriticalSection( &freetype_cs );
5742 size->cx = 0;
5743 WineEngGetTextMetrics(font, &tm);
5744 size->cy = tm.tmHeight;
5746 for(idx = 0; idx < count; idx++) {
5747 WineEngGetGlyphOutline(font, indices[idx],
5748 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5749 NULL);
5750 size->cx += FONT_GM(font,indices[idx])->adv;
5751 ext = size->cx;
5752 if (! pnfit || ext <= max_ext) {
5753 ++nfit;
5754 if (dxs)
5755 dxs[idx] = ext;
5759 if (pnfit)
5760 *pnfit = nfit;
5762 LeaveCriticalSection( &freetype_cs );
5763 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5764 return TRUE;
5767 /*************************************************************
5768 * WineEngGetFontData
5771 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5772 DWORD cbData)
5774 FT_Face ft_face = font->ft_face;
5775 FT_ULong len;
5776 FT_Error err;
5778 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5779 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5780 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5782 if(!FT_IS_SFNT(ft_face))
5783 return GDI_ERROR;
5785 if(!buf || !cbData)
5786 len = 0;
5787 else
5788 len = cbData;
5790 if(table) { /* MS tags differ in endianness from FT ones */
5791 table = table >> 24 | table << 24 |
5792 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5795 /* make sure value of len is the value freetype says it needs */
5796 if(buf && len)
5798 FT_ULong needed = 0;
5799 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5800 if( !err && needed < len) len = needed;
5802 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5804 if(err) {
5805 TRACE("Can't find table %c%c%c%c\n",
5806 /* bytes were reversed */
5807 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5808 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5809 return GDI_ERROR;
5811 return len;
5814 /*************************************************************
5815 * WineEngGetTextFace
5818 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5820 INT n = strlenW(font->name) + 1;
5821 if(str) {
5822 lstrcpynW(str, font->name, count);
5823 return min(count, n);
5824 } else
5825 return n;
5828 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5830 if (fs) *fs = font->fs;
5831 return font->charset;
5834 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5836 GdiFont *font = dc->gdiFont, *linked_font;
5837 struct list *first_hfont;
5838 BOOL ret;
5840 EnterCriticalSection( &freetype_cs );
5841 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5842 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5843 if(font == linked_font)
5844 *new_hfont = dc->hFont;
5845 else
5847 first_hfont = list_head(&linked_font->hfontlist);
5848 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5850 LeaveCriticalSection( &freetype_cs );
5851 return ret;
5854 /* Retrieve a list of supported Unicode ranges for a given font.
5855 * Can be called with NULL gs to calculate the buffer size. Returns
5856 * the number of ranges found.
5858 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5860 DWORD num_ranges = 0;
5862 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5864 FT_UInt glyph_code;
5865 FT_ULong char_code, char_code_prev;
5867 glyph_code = 0;
5868 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5870 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5871 face->num_glyphs, glyph_code, char_code);
5873 if (!glyph_code) return 0;
5875 if (gs)
5877 gs->ranges[0].wcLow = (USHORT)char_code;
5878 gs->ranges[0].cGlyphs = 0;
5879 gs->cGlyphsSupported = 0;
5882 num_ranges = 1;
5883 while (glyph_code)
5885 if (char_code < char_code_prev)
5887 ERR("expected increasing char code from FT_Get_Next_Char\n");
5888 return 0;
5890 if (char_code - char_code_prev > 1)
5892 num_ranges++;
5893 if (gs)
5895 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5896 gs->ranges[num_ranges - 1].cGlyphs = 1;
5897 gs->cGlyphsSupported++;
5900 else if (gs)
5902 gs->ranges[num_ranges - 1].cGlyphs++;
5903 gs->cGlyphsSupported++;
5905 char_code_prev = char_code;
5906 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5909 else
5910 FIXME("encoding %u not supported\n", face->charmap->encoding);
5912 return num_ranges;
5915 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5917 DWORD size = 0;
5918 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5920 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5921 if (glyphset)
5923 glyphset->cbThis = size;
5924 glyphset->cRanges = num_ranges;
5926 return size;
5929 /*************************************************************
5930 * FontIsLinked
5932 BOOL WineEngFontIsLinked(GdiFont *font)
5934 BOOL ret;
5935 EnterCriticalSection( &freetype_cs );
5936 ret = !list_empty(&font->child_fonts);
5937 LeaveCriticalSection( &freetype_cs );
5938 return ret;
5941 static BOOL is_hinting_enabled(void)
5943 /* Use the >= 2.2.0 function if available */
5944 if(pFT_Get_TrueType_Engine_Type)
5946 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5947 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5949 #ifdef FT_DRIVER_HAS_HINTER
5950 else
5952 FT_Module mod;
5954 /* otherwise if we've been compiled with < 2.2.0 headers
5955 use the internal macro */
5956 mod = pFT_Get_Module(library, "truetype");
5957 if(mod && FT_DRIVER_HAS_HINTER(mod))
5958 return TRUE;
5960 #endif
5962 return FALSE;
5965 static BOOL is_subpixel_rendering_enabled( void )
5967 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5968 return pFT_Library_SetLcdFilter &&
5969 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
5970 #else
5971 return FALSE;
5972 #endif
5975 /*************************************************************************
5976 * GetRasterizerCaps (GDI32.@)
5978 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5980 static int hinting = -1;
5981 static int subpixel = -1;
5983 if(hinting == -1)
5985 hinting = is_hinting_enabled();
5986 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5989 if ( subpixel == -1 )
5991 subpixel = is_subpixel_rendering_enabled();
5992 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
5995 lprs->nSize = sizeof(RASTERIZER_STATUS);
5996 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5997 if ( subpixel )
5998 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
5999 lprs->nLanguageID = 0;
6000 return TRUE;
6003 /*************************************************************
6004 * WineEngRealizationInfo
6006 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6008 FIXME("(%p, %p): stub!\n", font, info);
6010 info->flags = 1;
6011 if(FT_IS_SCALABLE(font->ft_face))
6012 info->flags |= 2;
6014 info->cache_num = font->cache_num;
6015 info->unknown2 = -1;
6016 return TRUE;
6019 /*************************************************************************
6020 * Kerning support for TrueType fonts
6022 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6024 struct TT_kern_table
6026 USHORT version;
6027 USHORT nTables;
6030 struct TT_kern_subtable
6032 USHORT version;
6033 USHORT length;
6034 union
6036 USHORT word;
6037 struct
6039 USHORT horizontal : 1;
6040 USHORT minimum : 1;
6041 USHORT cross_stream: 1;
6042 USHORT override : 1;
6043 USHORT reserved1 : 4;
6044 USHORT format : 8;
6045 } bits;
6046 } coverage;
6049 struct TT_format0_kern_subtable
6051 USHORT nPairs;
6052 USHORT searchRange;
6053 USHORT entrySelector;
6054 USHORT rangeShift;
6057 struct TT_kern_pair
6059 USHORT left;
6060 USHORT right;
6061 short value;
6064 static DWORD parse_format0_kern_subtable(GdiFont *font,
6065 const struct TT_format0_kern_subtable *tt_f0_ks,
6066 const USHORT *glyph_to_char,
6067 KERNINGPAIR *kern_pair, DWORD cPairs)
6069 USHORT i, nPairs;
6070 const struct TT_kern_pair *tt_kern_pair;
6072 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6074 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6076 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6077 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6078 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6080 if (!kern_pair || !cPairs)
6081 return nPairs;
6083 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6085 nPairs = min(nPairs, cPairs);
6087 for (i = 0; i < nPairs; i++)
6089 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6090 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6091 /* this algorithm appears to better match what Windows does */
6092 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6093 if (kern_pair->iKernAmount < 0)
6095 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6096 kern_pair->iKernAmount -= font->ppem;
6098 else if (kern_pair->iKernAmount > 0)
6100 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6101 kern_pair->iKernAmount += font->ppem;
6103 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6105 TRACE("left %u right %u value %d\n",
6106 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6108 kern_pair++;
6110 TRACE("copied %u entries\n", nPairs);
6111 return nPairs;
6114 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6116 DWORD length;
6117 void *buf;
6118 const struct TT_kern_table *tt_kern_table;
6119 const struct TT_kern_subtable *tt_kern_subtable;
6120 USHORT i, nTables;
6121 USHORT *glyph_to_char;
6123 EnterCriticalSection( &freetype_cs );
6124 if (font->total_kern_pairs != (DWORD)-1)
6126 if (cPairs && kern_pair)
6128 cPairs = min(cPairs, font->total_kern_pairs);
6129 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6130 LeaveCriticalSection( &freetype_cs );
6131 return cPairs;
6133 LeaveCriticalSection( &freetype_cs );
6134 return font->total_kern_pairs;
6137 font->total_kern_pairs = 0;
6139 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6141 if (length == GDI_ERROR)
6143 TRACE("no kerning data in the font\n");
6144 LeaveCriticalSection( &freetype_cs );
6145 return 0;
6148 buf = HeapAlloc(GetProcessHeap(), 0, length);
6149 if (!buf)
6151 WARN("Out of memory\n");
6152 LeaveCriticalSection( &freetype_cs );
6153 return 0;
6156 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6158 /* build a glyph index to char code map */
6159 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6160 if (!glyph_to_char)
6162 WARN("Out of memory allocating a glyph index to char code map\n");
6163 HeapFree(GetProcessHeap(), 0, buf);
6164 LeaveCriticalSection( &freetype_cs );
6165 return 0;
6168 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6170 FT_UInt glyph_code;
6171 FT_ULong char_code;
6173 glyph_code = 0;
6174 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6176 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6177 font->ft_face->num_glyphs, glyph_code, char_code);
6179 while (glyph_code)
6181 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6183 /* FIXME: This doesn't match what Windows does: it does some fancy
6184 * things with duplicate glyph index to char code mappings, while
6185 * we just avoid overriding existing entries.
6187 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6188 glyph_to_char[glyph_code] = (USHORT)char_code;
6190 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6193 else
6195 ULONG n;
6197 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6198 for (n = 0; n <= 65535; n++)
6199 glyph_to_char[n] = (USHORT)n;
6202 tt_kern_table = buf;
6203 nTables = GET_BE_WORD(tt_kern_table->nTables);
6204 TRACE("version %u, nTables %u\n",
6205 GET_BE_WORD(tt_kern_table->version), nTables);
6207 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6209 for (i = 0; i < nTables; i++)
6211 struct TT_kern_subtable tt_kern_subtable_copy;
6213 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6214 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6215 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6217 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6218 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6219 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6221 /* According to the TrueType specification this is the only format
6222 * that will be properly interpreted by Windows and OS/2
6224 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6226 DWORD new_chunk, old_total = font->total_kern_pairs;
6228 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6229 glyph_to_char, NULL, 0);
6230 font->total_kern_pairs += new_chunk;
6232 if (!font->kern_pairs)
6233 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6234 font->total_kern_pairs * sizeof(*font->kern_pairs));
6235 else
6236 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6237 font->total_kern_pairs * sizeof(*font->kern_pairs));
6239 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6240 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6242 else
6243 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6245 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6248 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6249 HeapFree(GetProcessHeap(), 0, buf);
6251 if (cPairs && kern_pair)
6253 cPairs = min(cPairs, font->total_kern_pairs);
6254 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6255 LeaveCriticalSection( &freetype_cs );
6256 return cPairs;
6258 LeaveCriticalSection( &freetype_cs );
6259 return font->total_kern_pairs;
6262 #else /* HAVE_FREETYPE */
6264 /*************************************************************************/
6266 BOOL WineEngInit(void)
6268 return FALSE;
6270 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6272 return NULL;
6274 BOOL WineEngDestroyFontInstance(HFONT hfont)
6276 return FALSE;
6279 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6281 return 1;
6284 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6285 LPWORD pgi, DWORD flags)
6287 return GDI_ERROR;
6290 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6291 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6292 const MAT2* lpmat)
6294 ERR("called but we don't have FreeType\n");
6295 return GDI_ERROR;
6298 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6300 ERR("called but we don't have FreeType\n");
6301 return FALSE;
6304 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6305 OUTLINETEXTMETRICW *potm)
6307 ERR("called but we don't have FreeType\n");
6308 return 0;
6311 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6312 LPINT buffer)
6314 ERR("called but we don't have FreeType\n");
6315 return FALSE;
6318 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6319 LPABC buffer)
6321 ERR("called but we don't have FreeType\n");
6322 return FALSE;
6325 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6326 LPABC buffer)
6328 ERR("called but we don't have FreeType\n");
6329 return FALSE;
6332 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6333 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6335 ERR("called but we don't have FreeType\n");
6336 return FALSE;
6339 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6340 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6342 ERR("called but we don't have FreeType\n");
6343 return FALSE;
6346 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6347 DWORD cbData)
6349 ERR("called but we don't have FreeType\n");
6350 return GDI_ERROR;
6353 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6355 ERR("called but we don't have FreeType\n");
6356 return 0;
6359 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6361 FIXME(":stub\n");
6362 return 1;
6365 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6367 FIXME(":stub\n");
6368 return TRUE;
6371 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6373 FIXME(":stub\n");
6374 return NULL;
6377 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6379 FIXME(":stub\n");
6380 return DEFAULT_CHARSET;
6383 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6385 return FALSE;
6388 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6390 FIXME("(%p, %p): stub\n", font, glyphset);
6391 return 0;
6394 BOOL WineEngFontIsLinked(GdiFont *font)
6396 return FALSE;
6399 /*************************************************************************
6400 * GetRasterizerCaps (GDI32.@)
6402 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6404 lprs->nSize = sizeof(RASTERIZER_STATUS);
6405 lprs->wFlags = 0;
6406 lprs->nLanguageID = 0;
6407 return TRUE;
6410 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6412 ERR("called but we don't have FreeType\n");
6413 return 0;
6416 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6418 ERR("called but we don't have FreeType\n");
6419 return FALSE;
6422 #endif /* HAVE_FREETYPE */