push 22b3e00525a9a3743634eb8f21ffe1bf98bf885e
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob2f2c63e5fb5aed10c9c44682b6f0253a7f8956ab
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 && !strcmpiW(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(!strcmpiW(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(!strcmpiW(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 memset(&fs, 0, sizeof(fs));
1655 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1656 psub = get_font_subst(&font_subst_list, value, -1);
1657 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1658 list_init(&font_link->links);
1659 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1661 WCHAR *face_name;
1662 CHILD_FONT *child_font;
1664 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1666 next = entry + strlenW(entry) + 1;
1668 face_name = strchrW(entry, ',');
1669 if(face_name)
1671 *face_name++ = 0;
1672 while(isspaceW(*face_name))
1673 face_name++;
1675 psub = get_font_subst(&font_subst_list, face_name, -1);
1676 if(psub)
1677 face_name = psub->to.name;
1679 face = find_face_from_filename(entry, face_name);
1680 if(!face)
1682 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1683 continue;
1686 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1687 child_font->face = face;
1688 child_font->font = NULL;
1689 fs.fsCsb[0] |= face->fs.fsCsb[0];
1690 fs.fsCsb[1] |= face->fs.fsCsb[1];
1691 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1692 list_add_tail(&font_link->links, &child_font->entry);
1694 family = find_family_from_name(font_link->font_name);
1695 if(family)
1697 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1699 face->fs_links = fs;
1702 list_add_tail(&system_links, &font_link->entry);
1703 val_len = max_val + 1;
1704 data_len = max_data;
1707 HeapFree(GetProcessHeap(), 0, value);
1708 HeapFree(GetProcessHeap(), 0, data);
1709 RegCloseKey(hkey);
1712 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1713 that Tahoma has */
1715 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1716 system_font_link->font_name = strdupW(System);
1717 list_init(&system_font_link->links);
1719 face = find_face_from_filename(tahoma_ttf, Tahoma);
1720 if(face)
1722 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1723 child_font->face = face;
1724 child_font->font = NULL;
1725 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1726 list_add_tail(&system_font_link->links, &child_font->entry);
1728 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1730 if(!strcmpiW(font_link->font_name, Tahoma))
1732 CHILD_FONT *font_link_entry;
1733 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1735 CHILD_FONT *new_child;
1736 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1737 new_child->face = font_link_entry->face;
1738 new_child->font = NULL;
1739 list_add_tail(&system_font_link->links, &new_child->entry);
1741 break;
1744 list_add_tail(&system_links, &system_font_link->entry);
1745 return ret;
1748 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1750 DIR *dir;
1751 struct dirent *dent;
1752 char path[MAX_PATH];
1754 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1756 dir = opendir(dirname);
1757 if(!dir) {
1758 WARN("Can't open directory %s\n", debugstr_a(dirname));
1759 return FALSE;
1761 while((dent = readdir(dir)) != NULL) {
1762 struct stat statbuf;
1764 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1765 continue;
1767 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1769 sprintf(path, "%s/%s", dirname, dent->d_name);
1771 if(stat(path, &statbuf) == -1)
1773 WARN("Can't stat %s\n", debugstr_a(path));
1774 continue;
1776 if(S_ISDIR(statbuf.st_mode))
1777 ReadFontDir(path, external_fonts);
1778 else
1779 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1781 closedir(dir);
1782 return TRUE;
1785 static void load_fontconfig_fonts(void)
1787 #ifdef SONAME_LIBFONTCONFIG
1788 void *fc_handle = NULL;
1789 FcConfig *config;
1790 FcPattern *pat;
1791 FcObjectSet *os;
1792 FcFontSet *fontset;
1793 int i, len;
1794 char *file;
1795 const char *ext;
1797 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1798 if(!fc_handle) {
1799 TRACE("Wine cannot find the fontconfig library (%s).\n",
1800 SONAME_LIBFONTCONFIG);
1801 return;
1803 #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;}
1804 LOAD_FUNCPTR(FcConfigGetCurrent);
1805 LOAD_FUNCPTR(FcFontList);
1806 LOAD_FUNCPTR(FcFontSetDestroy);
1807 LOAD_FUNCPTR(FcInit);
1808 LOAD_FUNCPTR(FcObjectSetAdd);
1809 LOAD_FUNCPTR(FcObjectSetCreate);
1810 LOAD_FUNCPTR(FcObjectSetDestroy);
1811 LOAD_FUNCPTR(FcPatternCreate);
1812 LOAD_FUNCPTR(FcPatternDestroy);
1813 LOAD_FUNCPTR(FcPatternGetBool);
1814 LOAD_FUNCPTR(FcPatternGetString);
1815 #undef LOAD_FUNCPTR
1817 if(!pFcInit()) return;
1819 config = pFcConfigGetCurrent();
1820 pat = pFcPatternCreate();
1821 os = pFcObjectSetCreate();
1822 pFcObjectSetAdd(os, FC_FILE);
1823 pFcObjectSetAdd(os, FC_SCALABLE);
1824 fontset = pFcFontList(config, pat, os);
1825 if(!fontset) return;
1826 for(i = 0; i < fontset->nfont; i++) {
1827 FcBool scalable;
1829 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1830 continue;
1831 TRACE("fontconfig: %s\n", file);
1833 /* We're just interested in OT/TT fonts for now, so this hack just
1834 picks up the scalable fonts without extensions .pf[ab] to save time
1835 loading every other font */
1837 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1839 TRACE("not scalable\n");
1840 continue;
1843 len = strlen( file );
1844 if(len < 4) continue;
1845 ext = &file[ len - 3 ];
1846 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1847 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1849 pFcFontSetDestroy(fontset);
1850 pFcObjectSetDestroy(os);
1851 pFcPatternDestroy(pat);
1852 sym_not_found:
1853 #endif
1854 return;
1857 static BOOL load_font_from_data_dir(LPCWSTR file)
1859 BOOL ret = FALSE;
1860 const char *data_dir = wine_get_data_dir();
1862 if (!data_dir) data_dir = wine_get_build_dir();
1864 if (data_dir)
1866 INT len;
1867 char *unix_name;
1869 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1871 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1873 strcpy(unix_name, data_dir);
1874 strcat(unix_name, "/fonts/");
1876 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1878 EnterCriticalSection( &freetype_cs );
1879 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1880 LeaveCriticalSection( &freetype_cs );
1881 HeapFree(GetProcessHeap(), 0, unix_name);
1883 return ret;
1886 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1888 static const WCHAR slashW[] = {'\\','\0'};
1889 BOOL ret = FALSE;
1890 WCHAR windowsdir[MAX_PATH];
1891 char *unixname;
1893 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1894 strcatW(windowsdir, fontsW);
1895 strcatW(windowsdir, slashW);
1896 strcatW(windowsdir, file);
1897 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1898 EnterCriticalSection( &freetype_cs );
1899 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1900 LeaveCriticalSection( &freetype_cs );
1901 HeapFree(GetProcessHeap(), 0, unixname);
1903 return ret;
1906 static void load_system_fonts(void)
1908 HKEY hkey;
1909 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1910 const WCHAR * const *value;
1911 DWORD dlen, type;
1912 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1913 char *unixname;
1915 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1916 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1917 strcatW(windowsdir, fontsW);
1918 for(value = SystemFontValues; *value; value++) {
1919 dlen = sizeof(data);
1920 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1921 type == REG_SZ) {
1922 BOOL added = FALSE;
1924 sprintfW(pathW, fmtW, windowsdir, data);
1925 if((unixname = wine_get_unix_file_name(pathW))) {
1926 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1927 HeapFree(GetProcessHeap(), 0, unixname);
1929 if (!added)
1930 load_font_from_data_dir(data);
1933 RegCloseKey(hkey);
1937 /*************************************************************
1939 * This adds registry entries for any externally loaded fonts
1940 * (fonts from fontconfig or FontDirs). It also deletes entries
1941 * of no longer existing fonts.
1944 static void update_reg_entries(void)
1946 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1947 LPWSTR valueW;
1948 DWORD len, len_fam;
1949 Family *family;
1950 Face *face;
1951 struct list *family_elem_ptr, *face_elem_ptr;
1952 WCHAR *file;
1953 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1954 static const WCHAR spaceW[] = {' ', '\0'};
1955 char *path;
1957 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1958 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1959 ERR("Can't create Windows font reg key\n");
1960 goto end;
1963 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1964 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1965 ERR("Can't create Windows font reg key\n");
1966 goto end;
1969 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1970 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1971 ERR("Can't create external font reg key\n");
1972 goto end;
1975 /* enumerate the fonts and add external ones to the two keys */
1977 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1978 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1979 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1980 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1981 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1982 if(!face->external) continue;
1983 len = len_fam;
1984 if (!(face->ntmFlags & NTM_REGULAR))
1985 len = len_fam + strlenW(face->StyleName) + 1;
1986 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1987 strcpyW(valueW, family->FamilyName);
1988 if(len != len_fam) {
1989 strcatW(valueW, spaceW);
1990 strcatW(valueW, face->StyleName);
1992 strcatW(valueW, TrueType);
1994 file = wine_get_dos_file_name(face->file);
1995 if(file)
1996 len = strlenW(file) + 1;
1997 else
1999 if((path = strrchr(face->file, '/')) == NULL)
2000 path = face->file;
2001 else
2002 path++;
2003 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2005 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2006 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2008 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2009 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2010 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2012 HeapFree(GetProcessHeap(), 0, file);
2013 HeapFree(GetProcessHeap(), 0, valueW);
2016 end:
2017 if(external_key) RegCloseKey(external_key);
2018 if(win9x_key) RegCloseKey(win9x_key);
2019 if(winnt_key) RegCloseKey(winnt_key);
2020 return;
2023 static void delete_external_font_keys(void)
2025 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2026 DWORD dlen, vlen, datalen, valuelen, i, type;
2027 LPWSTR valueW;
2028 LPVOID data;
2030 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2031 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2032 ERR("Can't create Windows font reg key\n");
2033 goto end;
2036 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2037 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2038 ERR("Can't create Windows font reg key\n");
2039 goto end;
2042 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2043 ERR("Can't create external font reg key\n");
2044 goto end;
2047 /* Delete all external fonts added last time */
2049 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2050 &valuelen, &datalen, NULL, NULL);
2051 valuelen++; /* returned value doesn't include room for '\0' */
2052 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2053 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2055 dlen = datalen * sizeof(WCHAR);
2056 vlen = valuelen;
2057 i = 0;
2058 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2059 &dlen) == ERROR_SUCCESS) {
2061 RegDeleteValueW(winnt_key, valueW);
2062 RegDeleteValueW(win9x_key, valueW);
2063 /* reset dlen and vlen */
2064 dlen = datalen;
2065 vlen = valuelen;
2067 HeapFree(GetProcessHeap(), 0, data);
2068 HeapFree(GetProcessHeap(), 0, valueW);
2070 /* Delete the old external fonts key */
2071 RegCloseKey(external_key);
2072 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2074 end:
2075 if(win9x_key) RegCloseKey(win9x_key);
2076 if(winnt_key) RegCloseKey(winnt_key);
2079 /*************************************************************
2080 * WineEngAddFontResourceEx
2083 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2085 INT ret = 0;
2087 GDI_CheckNotLock();
2089 if (ft_handle) /* do it only if we have freetype up and running */
2091 char *unixname;
2093 if(flags)
2094 FIXME("Ignoring flags %x\n", flags);
2096 if((unixname = wine_get_unix_file_name(file)))
2098 EnterCriticalSection( &freetype_cs );
2099 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2100 LeaveCriticalSection( &freetype_cs );
2101 HeapFree(GetProcessHeap(), 0, unixname);
2103 if (!ret && !strchrW(file, '\\')) {
2104 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2105 ret = load_font_from_winfonts_dir(file);
2106 if (!ret) {
2107 /* Try in datadir/fonts (or builddir/fonts),
2108 * needed for Magic the Gathering Online
2110 ret = load_font_from_data_dir(file);
2114 return ret;
2117 /*************************************************************
2118 * WineEngAddFontMemResourceEx
2121 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2123 GDI_CheckNotLock();
2125 if (ft_handle) /* do it only if we have freetype up and running */
2127 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2129 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2130 memcpy(pFontCopy, pbFont, cbFont);
2132 EnterCriticalSection( &freetype_cs );
2133 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2134 LeaveCriticalSection( &freetype_cs );
2136 if (*pcFonts == 0)
2138 TRACE("AddFontToList failed\n");
2139 HeapFree(GetProcessHeap(), 0, pFontCopy);
2140 return NULL;
2142 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2143 * For now return something unique but quite random
2145 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2146 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2149 *pcFonts = 0;
2150 return 0;
2153 /*************************************************************
2154 * WineEngRemoveFontResourceEx
2157 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2159 GDI_CheckNotLock();
2160 FIXME(":stub\n");
2161 return TRUE;
2164 static const struct nls_update_font_list
2166 UINT ansi_cp, oem_cp;
2167 const char *oem, *fixed, *system;
2168 const char *courier, *serif, *small, *sserif;
2169 /* these are for font substitutes */
2170 const char *shelldlg, *tmsrmn;
2171 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2172 *helv_0, *tmsrmn_0;
2173 const struct subst
2175 const char *from, *to;
2176 } arial_0, courier_new_0, times_new_roman_0;
2177 } nls_update_font_list[] =
2179 /* Latin 1 (United States) */
2180 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2181 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2182 "Tahoma","Times New Roman",
2183 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2184 { 0 }, { 0 }, { 0 }
2186 /* Latin 1 (Multilingual) */
2187 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2188 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2189 "Tahoma","Times New Roman", /* FIXME unverified */
2190 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2191 { 0 }, { 0 }, { 0 }
2193 /* Eastern Europe */
2194 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2195 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2196 "Tahoma","Times New Roman", /* FIXME unverified */
2197 "Fixedsys,238", "System,238",
2198 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2199 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2200 { "Arial CE,0", "Arial,238" },
2201 { "Courier New CE,0", "Courier New,238" },
2202 { "Times New Roman CE,0", "Times New Roman,238" }
2204 /* Cyrillic */
2205 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2206 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2207 "Tahoma","Times New Roman", /* FIXME unverified */
2208 "Fixedsys,204", "System,204",
2209 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2210 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2211 { "Arial Cyr,0", "Arial,204" },
2212 { "Courier New Cyr,0", "Courier New,204" },
2213 { "Times New Roman Cyr,0", "Times New Roman,204" }
2215 /* Greek */
2216 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2217 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2218 "Tahoma","Times New Roman", /* FIXME unverified */
2219 "Fixedsys,161", "System,161",
2220 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2221 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2222 { "Arial Greek,0", "Arial,161" },
2223 { "Courier New Greek,0", "Courier New,161" },
2224 { "Times New Roman Greek,0", "Times New Roman,161" }
2226 /* Turkish */
2227 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2228 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2229 "Tahoma","Times New Roman", /* FIXME unverified */
2230 "Fixedsys,162", "System,162",
2231 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2232 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2233 { "Arial Tur,0", "Arial,162" },
2234 { "Courier New Tur,0", "Courier New,162" },
2235 { "Times New Roman Tur,0", "Times New Roman,162" }
2237 /* Hebrew */
2238 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2239 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2240 "Tahoma","Times New Roman", /* FIXME unverified */
2241 "Fixedsys,177", "System,177",
2242 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2243 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2244 { 0 }, { 0 }, { 0 }
2246 /* Arabic */
2247 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2248 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2249 "Tahoma","Times New Roman", /* FIXME unverified */
2250 "Fixedsys,178", "System,178",
2251 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2252 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2253 { 0 }, { 0 }, { 0 }
2255 /* Baltic */
2256 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2257 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2258 "Tahoma","Times New Roman", /* FIXME unverified */
2259 "Fixedsys,186", "System,186",
2260 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2261 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2262 { "Arial Baltic,0", "Arial,186" },
2263 { "Courier New Baltic,0", "Courier New,186" },
2264 { "Times New Roman Baltic,0", "Times New Roman,186" }
2266 /* Vietnamese */
2267 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2268 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2269 "Tahoma","Times New Roman", /* FIXME unverified */
2270 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2271 { 0 }, { 0 }, { 0 }
2273 /* Thai */
2274 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2275 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2276 "Tahoma","Times New Roman", /* FIXME unverified */
2277 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2278 { 0 }, { 0 }, { 0 }
2280 /* Japanese */
2281 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2282 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2283 "MS UI Gothic","MS Serif",
2284 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2285 { 0 }, { 0 }, { 0 }
2287 /* Chinese Simplified */
2288 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2289 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2290 "SimSun", "NSimSun",
2291 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2292 { 0 }, { 0 }, { 0 }
2294 /* Korean */
2295 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2296 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2297 "Gulim", "Batang",
2298 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2299 { 0 }, { 0 }, { 0 }
2301 /* Chinese Traditional */
2302 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2303 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2304 "PMingLiU", "MingLiU",
2305 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2306 { 0 }, { 0 }, { 0 }
2310 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2312 return ( ansi_cp == 932 /* CP932 for Japanese */
2313 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2314 || ansi_cp == 949 /* CP949 for Korean */
2315 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2318 static inline HKEY create_fonts_NT_registry_key(void)
2320 HKEY hkey = 0;
2322 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2323 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2324 return hkey;
2327 static inline HKEY create_fonts_9x_registry_key(void)
2329 HKEY hkey = 0;
2331 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2332 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2333 return hkey;
2336 static inline HKEY create_config_fonts_registry_key(void)
2338 HKEY hkey = 0;
2340 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2341 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2342 return hkey;
2345 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2347 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2348 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2349 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2350 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2353 static void set_value_key(HKEY hkey, const char *name, const char *value)
2355 if (value)
2356 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2357 else if (name)
2358 RegDeleteValueA(hkey, name);
2361 static void update_font_info(void)
2363 char buf[40], cpbuf[40];
2364 DWORD len, type;
2365 HKEY hkey = 0;
2366 UINT i, ansi_cp = 0, oem_cp = 0;
2367 BOOL done = FALSE;
2369 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2370 return;
2372 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2373 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2374 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2375 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2376 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2378 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2379 if (is_dbcs_ansi_cp(ansi_cp))
2380 use_default_fallback = TRUE;
2382 len = sizeof(buf);
2383 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2385 if (!strcmp( buf, cpbuf )) /* already set correctly */
2387 RegCloseKey(hkey);
2388 return;
2390 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2392 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2394 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2395 RegCloseKey(hkey);
2397 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2399 HKEY hkey;
2401 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2402 nls_update_font_list[i].oem_cp == oem_cp)
2404 hkey = create_config_fonts_registry_key();
2405 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2406 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2407 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2408 RegCloseKey(hkey);
2410 hkey = create_fonts_NT_registry_key();
2411 add_font_list(hkey, &nls_update_font_list[i]);
2412 RegCloseKey(hkey);
2414 hkey = create_fonts_9x_registry_key();
2415 add_font_list(hkey, &nls_update_font_list[i]);
2416 RegCloseKey(hkey);
2418 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2420 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2421 strlen(nls_update_font_list[i].shelldlg)+1);
2422 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2423 strlen(nls_update_font_list[i].tmsrmn)+1);
2425 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2426 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2427 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2428 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2429 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2430 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2431 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2432 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2434 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2435 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2436 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2438 RegCloseKey(hkey);
2440 done = TRUE;
2442 else
2444 /* Delete the FontSubstitutes from other locales */
2445 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2447 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2448 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2449 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2450 RegCloseKey(hkey);
2454 if (!done)
2455 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2459 static BOOL init_freetype(void)
2461 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2462 if(!ft_handle) {
2463 WINE_MESSAGE(
2464 "Wine cannot find the FreeType font library. To enable Wine to\n"
2465 "use TrueType fonts please install a version of FreeType greater than\n"
2466 "or equal to 2.0.5.\n"
2467 "http://www.freetype.org\n");
2468 return FALSE;
2471 #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;}
2473 LOAD_FUNCPTR(FT_Vector_Unit)
2474 LOAD_FUNCPTR(FT_Done_Face)
2475 LOAD_FUNCPTR(FT_Get_Char_Index)
2476 LOAD_FUNCPTR(FT_Get_Module)
2477 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2478 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2479 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2480 LOAD_FUNCPTR(FT_Init_FreeType)
2481 LOAD_FUNCPTR(FT_Load_Glyph)
2482 LOAD_FUNCPTR(FT_Matrix_Multiply)
2483 #ifndef FT_MULFIX_INLINED
2484 LOAD_FUNCPTR(FT_MulFix)
2485 #endif
2486 LOAD_FUNCPTR(FT_New_Face)
2487 LOAD_FUNCPTR(FT_New_Memory_Face)
2488 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2489 LOAD_FUNCPTR(FT_Outline_Transform)
2490 LOAD_FUNCPTR(FT_Outline_Translate)
2491 LOAD_FUNCPTR(FT_Select_Charmap)
2492 LOAD_FUNCPTR(FT_Set_Charmap)
2493 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2494 LOAD_FUNCPTR(FT_Vector_Transform)
2495 LOAD_FUNCPTR(FT_Render_Glyph)
2497 #undef LOAD_FUNCPTR
2498 /* Don't warn if these ones are missing */
2499 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2500 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2501 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2502 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2503 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2504 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2505 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2506 #endif
2507 #ifdef HAVE_FREETYPE_FTWINFNT_H
2508 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2509 #endif
2510 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2511 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2512 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2513 <= 2.0.3 has FT_Sqrt64 */
2514 goto sym_not_found;
2517 if(pFT_Init_FreeType(&library) != 0) {
2518 ERR("Can't init FreeType library\n");
2519 wine_dlclose(ft_handle, NULL, 0);
2520 ft_handle = NULL;
2521 return FALSE;
2523 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2524 if (pFT_Library_Version)
2525 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2527 if (FT_Version.major<=0)
2529 FT_Version.major=2;
2530 FT_Version.minor=0;
2531 FT_Version.patch=5;
2533 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2534 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2535 ((FT_Version.minor << 8) & 0x00ff00) |
2536 ((FT_Version.patch ) & 0x0000ff);
2538 return TRUE;
2540 sym_not_found:
2541 WINE_MESSAGE(
2542 "Wine cannot find certain functions that it needs inside the FreeType\n"
2543 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2544 "FreeType to at least version 2.0.5.\n"
2545 "http://www.freetype.org\n");
2546 wine_dlclose(ft_handle, NULL, 0);
2547 ft_handle = NULL;
2548 return FALSE;
2551 /*************************************************************
2552 * WineEngInit
2554 * Initialize FreeType library and create a list of available faces
2556 BOOL WineEngInit(void)
2558 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2559 static const WCHAR pathW[] = {'P','a','t','h',0};
2560 HKEY hkey;
2561 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2562 WCHAR windowsdir[MAX_PATH];
2563 char *unixname;
2564 HANDLE font_mutex;
2565 const char *data_dir;
2567 TRACE("\n");
2569 /* update locale dependent font info in registry */
2570 update_font_info();
2572 if(!init_freetype()) return FALSE;
2574 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2575 ERR("Failed to create font mutex\n");
2576 return FALSE;
2578 WaitForSingleObject(font_mutex, INFINITE);
2580 delete_external_font_keys();
2582 /* load the system bitmap fonts */
2583 load_system_fonts();
2585 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2586 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2587 strcatW(windowsdir, fontsW);
2588 if((unixname = wine_get_unix_file_name(windowsdir)))
2590 ReadFontDir(unixname, FALSE);
2591 HeapFree(GetProcessHeap(), 0, unixname);
2594 /* load the system truetype fonts */
2595 data_dir = wine_get_data_dir();
2596 if (!data_dir) data_dir = wine_get_build_dir();
2597 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2598 strcpy(unixname, data_dir);
2599 strcat(unixname, "/fonts/");
2600 ReadFontDir(unixname, TRUE);
2601 HeapFree(GetProcessHeap(), 0, unixname);
2604 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2605 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2606 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2607 will skip these. */
2608 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2609 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2610 &hkey) == ERROR_SUCCESS) {
2611 LPWSTR data, valueW;
2612 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2613 &valuelen, &datalen, NULL, NULL);
2615 valuelen++; /* returned value doesn't include room for '\0' */
2616 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2617 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2618 if (valueW && data)
2620 dlen = datalen * sizeof(WCHAR);
2621 vlen = valuelen;
2622 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2623 &dlen) == ERROR_SUCCESS) {
2624 if(data[0] && (data[1] == ':'))
2626 if((unixname = wine_get_unix_file_name(data)))
2628 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2629 HeapFree(GetProcessHeap(), 0, unixname);
2632 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2634 WCHAR pathW[MAX_PATH];
2635 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2636 BOOL added = FALSE;
2638 sprintfW(pathW, fmtW, windowsdir, data);
2639 if((unixname = wine_get_unix_file_name(pathW)))
2641 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2642 HeapFree(GetProcessHeap(), 0, unixname);
2644 if (!added)
2645 load_font_from_data_dir(data);
2647 /* reset dlen and vlen */
2648 dlen = datalen;
2649 vlen = valuelen;
2652 HeapFree(GetProcessHeap(), 0, data);
2653 HeapFree(GetProcessHeap(), 0, valueW);
2654 RegCloseKey(hkey);
2657 load_fontconfig_fonts();
2659 /* then look in any directories that we've specified in the config file */
2660 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2661 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2663 DWORD len;
2664 LPWSTR valueW;
2665 LPSTR valueA, ptr;
2667 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2669 len += sizeof(WCHAR);
2670 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2671 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2673 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2674 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2675 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2676 TRACE( "got font path %s\n", debugstr_a(valueA) );
2677 ptr = valueA;
2678 while (ptr)
2680 LPSTR next = strchr( ptr, ':' );
2681 if (next) *next++ = 0;
2682 ReadFontDir( ptr, TRUE );
2683 ptr = next;
2685 HeapFree( GetProcessHeap(), 0, valueA );
2687 HeapFree( GetProcessHeap(), 0, valueW );
2689 RegCloseKey(hkey);
2692 DumpFontList();
2693 LoadSubstList();
2694 DumpSubstList();
2695 LoadReplaceList();
2696 update_reg_entries();
2698 init_system_links();
2700 ReleaseMutex(font_mutex);
2701 return TRUE;
2705 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2707 TT_OS2 *pOS2;
2708 TT_HoriHeader *pHori;
2710 LONG ppem;
2712 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2713 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2715 if(height == 0) height = 16;
2717 /* Calc. height of EM square:
2719 * For +ve lfHeight we have
2720 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2721 * Re-arranging gives:
2722 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2724 * For -ve lfHeight we have
2725 * |lfHeight| = ppem
2726 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2727 * with il = winAscent + winDescent - units_per_em]
2731 if(height > 0) {
2732 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2733 ppem = MulDiv(ft_face->units_per_EM, height,
2734 pHori->Ascender - pHori->Descender);
2735 else
2736 ppem = MulDiv(ft_face->units_per_EM, height,
2737 pOS2->usWinAscent + pOS2->usWinDescent);
2739 else
2740 ppem = -height;
2742 return ppem;
2745 static struct font_mapping *map_font_file( const char *name )
2747 struct font_mapping *mapping;
2748 struct stat st;
2749 int fd;
2751 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2752 if (fstat( fd, &st ) == -1) goto error;
2754 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2756 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2758 mapping->refcount++;
2759 close( fd );
2760 return mapping;
2763 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2764 goto error;
2766 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2767 close( fd );
2769 if (mapping->data == MAP_FAILED)
2771 HeapFree( GetProcessHeap(), 0, mapping );
2772 return NULL;
2774 mapping->refcount = 1;
2775 mapping->dev = st.st_dev;
2776 mapping->ino = st.st_ino;
2777 mapping->size = st.st_size;
2778 list_add_tail( &mappings_list, &mapping->entry );
2779 return mapping;
2781 error:
2782 close( fd );
2783 return NULL;
2786 static void unmap_font_file( struct font_mapping *mapping )
2788 if (!--mapping->refcount)
2790 list_remove( &mapping->entry );
2791 munmap( mapping->data, mapping->size );
2792 HeapFree( GetProcessHeap(), 0, mapping );
2796 static LONG load_VDMX(GdiFont*, LONG);
2798 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2800 FT_Error err;
2801 FT_Face ft_face;
2802 void *data_ptr;
2803 DWORD data_size;
2805 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2807 if (face->file)
2809 if (!(font->mapping = map_font_file( face->file )))
2811 WARN("failed to map %s\n", debugstr_a(face->file));
2812 return 0;
2814 data_ptr = font->mapping->data;
2815 data_size = font->mapping->size;
2817 else
2819 data_ptr = face->font_data_ptr;
2820 data_size = face->font_data_size;
2823 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2824 if(err) {
2825 ERR("FT_New_Face rets %d\n", err);
2826 return 0;
2829 /* set it here, as load_VDMX needs it */
2830 font->ft_face = ft_face;
2832 if(FT_IS_SCALABLE(ft_face)) {
2833 /* load the VDMX table if we have one */
2834 font->ppem = load_VDMX(font, height);
2835 if(font->ppem == 0)
2836 font->ppem = calc_ppem_for_height(ft_face, height);
2837 TRACE("height %d => ppem %d\n", height, font->ppem);
2839 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2840 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2841 } else {
2842 font->ppem = height;
2843 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2844 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2846 return ft_face;
2850 static int get_nearest_charset(Face *face, int *cp)
2852 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2853 a single face with the requested charset. The idea is to check if
2854 the selected font supports the current ANSI codepage, if it does
2855 return the corresponding charset, else return the first charset */
2857 CHARSETINFO csi;
2858 int acp = GetACP(), i;
2859 DWORD fs0;
2861 *cp = acp;
2862 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2863 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2864 return csi.ciCharset;
2866 for(i = 0; i < 32; i++) {
2867 fs0 = 1L << i;
2868 if(face->fs.fsCsb[0] & fs0) {
2869 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2870 *cp = csi.ciACP;
2871 return csi.ciCharset;
2873 else
2874 FIXME("TCI failing on %x\n", fs0);
2878 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2879 face->fs.fsCsb[0], face->file);
2880 *cp = acp;
2881 return DEFAULT_CHARSET;
2884 static GdiFont *alloc_font(void)
2886 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2887 ret->gmsize = 1;
2888 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2889 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2890 ret->potm = NULL;
2891 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2892 ret->total_kern_pairs = (DWORD)-1;
2893 ret->kern_pairs = NULL;
2894 list_init(&ret->hfontlist);
2895 list_init(&ret->child_fonts);
2896 return ret;
2899 static void free_font(GdiFont *font)
2901 struct list *cursor, *cursor2;
2902 DWORD i;
2904 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2906 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2907 struct list *first_hfont;
2908 HFONTLIST *hfontlist;
2909 list_remove(cursor);
2910 if(child->font)
2912 first_hfont = list_head(&child->font->hfontlist);
2913 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2914 DeleteObject(hfontlist->hfont);
2915 HeapFree(GetProcessHeap(), 0, hfontlist);
2916 free_font(child->font);
2918 HeapFree(GetProcessHeap(), 0, child);
2921 if (font->ft_face) pFT_Done_Face(font->ft_face);
2922 if (font->mapping) unmap_font_file( font->mapping );
2923 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2924 HeapFree(GetProcessHeap(), 0, font->potm);
2925 HeapFree(GetProcessHeap(), 0, font->name);
2926 for (i = 0; i < font->gmsize; i++)
2927 HeapFree(GetProcessHeap(),0,font->gm[i]);
2928 HeapFree(GetProcessHeap(), 0, font->gm);
2929 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2930 HeapFree(GetProcessHeap(), 0, font);
2934 /*************************************************************
2935 * load_VDMX
2937 * load the vdmx entry for the specified height
2940 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2941 ( ( (FT_ULong)_x4 << 24 ) | \
2942 ( (FT_ULong)_x3 << 16 ) | \
2943 ( (FT_ULong)_x2 << 8 ) | \
2944 (FT_ULong)_x1 )
2946 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2948 typedef struct {
2949 BYTE bCharSet;
2950 BYTE xRatio;
2951 BYTE yStartRatio;
2952 BYTE yEndRatio;
2953 } Ratios;
2955 typedef struct {
2956 WORD recs;
2957 BYTE startsz;
2958 BYTE endsz;
2959 } VDMX_group;
2961 static LONG load_VDMX(GdiFont *font, LONG height)
2963 WORD hdr[3], tmp;
2964 VDMX_group group;
2965 BYTE devXRatio, devYRatio;
2966 USHORT numRecs, numRatios;
2967 DWORD result, offset = -1;
2968 LONG ppem = 0;
2969 int i;
2971 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2973 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2974 return ppem;
2976 /* FIXME: need the real device aspect ratio */
2977 devXRatio = 1;
2978 devYRatio = 1;
2980 numRecs = GET_BE_WORD(hdr[1]);
2981 numRatios = GET_BE_WORD(hdr[2]);
2983 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2984 for(i = 0; i < numRatios; i++) {
2985 Ratios ratio;
2987 offset = (3 * 2) + (i * sizeof(Ratios));
2988 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2989 offset = -1;
2991 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2993 if((ratio.xRatio == 0 &&
2994 ratio.yStartRatio == 0 &&
2995 ratio.yEndRatio == 0) ||
2996 (devXRatio == ratio.xRatio &&
2997 devYRatio >= ratio.yStartRatio &&
2998 devYRatio <= ratio.yEndRatio))
3000 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3001 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3002 offset = GET_BE_WORD(tmp);
3003 break;
3007 if(offset == -1) {
3008 FIXME("No suitable ratio found\n");
3009 return ppem;
3012 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3013 USHORT recs;
3014 BYTE startsz, endsz;
3015 WORD *vTable;
3017 recs = GET_BE_WORD(group.recs);
3018 startsz = group.startsz;
3019 endsz = group.endsz;
3021 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3023 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3024 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3025 if(result == GDI_ERROR) {
3026 FIXME("Failed to retrieve vTable\n");
3027 goto end;
3030 if(height > 0) {
3031 for(i = 0; i < recs; i++) {
3032 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3033 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3034 ppem = GET_BE_WORD(vTable[i * 3]);
3036 if(yMax + -yMin == height) {
3037 font->yMax = yMax;
3038 font->yMin = yMin;
3039 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3040 break;
3042 if(yMax + -yMin > height) {
3043 if(--i < 0) {
3044 ppem = 0;
3045 goto end; /* failed */
3047 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3048 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3049 ppem = GET_BE_WORD(vTable[i * 3]);
3050 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3051 break;
3054 if(!font->yMax) {
3055 ppem = 0;
3056 TRACE("ppem not found for height %d\n", height);
3058 } else {
3059 ppem = -height;
3060 if(ppem < startsz || ppem > endsz)
3061 goto end;
3063 for(i = 0; i < recs; i++) {
3064 USHORT yPelHeight;
3065 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3067 if(yPelHeight > ppem)
3068 break; /* failed */
3070 if(yPelHeight == ppem) {
3071 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3072 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3073 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3074 break;
3078 end:
3079 HeapFree(GetProcessHeap(), 0, vTable);
3082 return ppem;
3085 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3087 if(font->font_desc.hash != fd->hash) return TRUE;
3088 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3089 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3090 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3091 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3094 static void calc_hash(FONT_DESC *pfd)
3096 DWORD hash = 0, *ptr, two_chars;
3097 WORD *pwc;
3098 unsigned int i;
3100 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3101 hash ^= *ptr;
3102 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3103 hash ^= *ptr;
3104 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3105 two_chars = *ptr;
3106 pwc = (WCHAR *)&two_chars;
3107 if(!*pwc) break;
3108 *pwc = toupperW(*pwc);
3109 pwc++;
3110 *pwc = toupperW(*pwc);
3111 hash ^= two_chars;
3112 if(!*pwc) break;
3114 hash ^= !pfd->can_use_bitmap;
3115 pfd->hash = hash;
3116 return;
3119 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3121 GdiFont *ret;
3122 FONT_DESC fd;
3123 HFONTLIST *hflist;
3124 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3126 fd.lf = *plf;
3127 fd.matrix = *pmat;
3128 fd.can_use_bitmap = can_use_bitmap;
3129 calc_hash(&fd);
3131 /* try the child list */
3132 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3133 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3134 if(!fontcmp(ret, &fd)) {
3135 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3136 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3137 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3138 if(hflist->hfont == hfont)
3139 return ret;
3144 /* try the in-use list */
3145 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3146 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3147 if(!fontcmp(ret, &fd)) {
3148 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3149 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3150 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3151 if(hflist->hfont == hfont)
3152 return ret;
3154 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3155 hflist->hfont = hfont;
3156 list_add_head(&ret->hfontlist, &hflist->entry);
3157 return ret;
3161 /* then the unused list */
3162 font_elem_ptr = list_head(&unused_gdi_font_list);
3163 while(font_elem_ptr) {
3164 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3165 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3166 if(!fontcmp(ret, &fd)) {
3167 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3168 assert(list_empty(&ret->hfontlist));
3169 TRACE("Found %p in unused list\n", ret);
3170 list_remove(&ret->entry);
3171 list_add_head(&gdi_font_list, &ret->entry);
3172 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3173 hflist->hfont = hfont;
3174 list_add_head(&ret->hfontlist, &hflist->entry);
3175 return ret;
3178 return NULL;
3181 static void add_to_cache(GdiFont *font)
3183 static DWORD cache_num = 1;
3185 font->cache_num = cache_num++;
3186 list_add_head(&gdi_font_list, &font->entry);
3189 /*************************************************************
3190 * create_child_font_list
3192 static BOOL create_child_font_list(GdiFont *font)
3194 BOOL ret = FALSE;
3195 SYSTEM_LINKS *font_link;
3196 CHILD_FONT *font_link_entry, *new_child;
3198 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3200 if(!strcmpiW(font_link->font_name, font->name))
3202 TRACE("found entry in system list\n");
3203 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3205 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3206 new_child->face = font_link_entry->face;
3207 new_child->font = NULL;
3208 list_add_tail(&font->child_fonts, &new_child->entry);
3209 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3211 ret = TRUE;
3212 break;
3216 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3217 * Sans Serif. This is how asian windows get default fallbacks for fonts
3219 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3220 font->charset != OEM_CHARSET &&
3221 strcmpiW(font->name,szDefaultFallbackLink) != 0)
3222 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3224 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3226 TRACE("found entry in default fallback list\n");
3227 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3229 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3230 new_child->face = font_link_entry->face;
3231 new_child->font = NULL;
3232 list_add_tail(&font->child_fonts, &new_child->entry);
3233 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3235 ret = TRUE;
3236 break;
3240 return ret;
3243 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3245 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3247 if (pFT_Set_Charmap)
3249 FT_Int i;
3250 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3252 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3254 for (i = 0; i < ft_face->num_charmaps; i++)
3256 if (ft_face->charmaps[i]->encoding == encoding)
3258 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3259 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3261 switch (ft_face->charmaps[i]->platform_id)
3263 default:
3264 cmap_def = ft_face->charmaps[i];
3265 break;
3266 case 0: /* Apple Unicode */
3267 cmap0 = ft_face->charmaps[i];
3268 break;
3269 case 1: /* Macintosh */
3270 cmap1 = ft_face->charmaps[i];
3271 break;
3272 case 2: /* ISO */
3273 cmap2 = ft_face->charmaps[i];
3274 break;
3275 case 3: /* Microsoft */
3276 cmap3 = ft_face->charmaps[i];
3277 break;
3281 if (cmap3) /* prefer Microsoft cmap table */
3282 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3283 else if (cmap1)
3284 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3285 else if (cmap2)
3286 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3287 else if (cmap0)
3288 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3289 else if (cmap_def)
3290 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3292 return ft_err == FT_Err_Ok;
3295 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3298 /*************************************************************
3299 * WineEngCreateFontInstance
3302 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3304 GdiFont *ret;
3305 Face *face, *best, *best_bitmap;
3306 Family *family, *last_resort_family;
3307 struct list *family_elem_ptr, *face_elem_ptr;
3308 INT height, width = 0;
3309 unsigned int score = 0, new_score;
3310 signed int diff = 0, newdiff;
3311 BOOL bd, it, can_use_bitmap;
3312 LOGFONTW lf;
3313 CHARSETINFO csi;
3314 HFONTLIST *hflist;
3315 FMAT2 dcmat;
3316 FontSubst *psub = NULL;
3318 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3319 lf.lfWidth = abs(lf.lfWidth);
3321 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3323 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3324 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3325 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3326 lf.lfEscapement);
3328 if(dc->GraphicsMode == GM_ADVANCED)
3329 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3330 else
3332 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3333 font scaling abilities. */
3334 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3335 dcmat.eM21 = dcmat.eM12 = 0;
3338 /* Try to avoid not necessary glyph transformations */
3339 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3341 lf.lfHeight *= fabs(dcmat.eM11);
3342 lf.lfWidth *= fabs(dcmat.eM11);
3343 dcmat.eM11 = dcmat.eM22 = 1.0;
3346 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3347 dcmat.eM21, dcmat.eM22);
3349 GDI_CheckNotLock();
3350 EnterCriticalSection( &freetype_cs );
3352 /* check the cache first */
3353 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3354 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3355 LeaveCriticalSection( &freetype_cs );
3356 return ret;
3359 TRACE("not in cache\n");
3360 if(list_empty(&font_list)) /* No fonts installed */
3362 TRACE("No fonts installed\n");
3363 LeaveCriticalSection( &freetype_cs );
3364 return NULL;
3366 if(!have_installed_roman_font)
3368 TRACE("No roman font installed\n");
3369 LeaveCriticalSection( &freetype_cs );
3370 return NULL;
3373 ret = alloc_font();
3375 ret->font_desc.matrix = dcmat;
3376 ret->font_desc.lf = lf;
3377 ret->font_desc.can_use_bitmap = can_use_bitmap;
3378 calc_hash(&ret->font_desc);
3379 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3380 hflist->hfont = hfont;
3381 list_add_head(&ret->hfontlist, &hflist->entry);
3383 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3384 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3385 original value lfCharSet. Note this is a special case for
3386 Symbol and doesn't happen at least for "Wingdings*" */
3388 if(!strcmpiW(lf.lfFaceName, SymbolW))
3389 lf.lfCharSet = SYMBOL_CHARSET;
3391 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3392 switch(lf.lfCharSet) {
3393 case DEFAULT_CHARSET:
3394 csi.fs.fsCsb[0] = 0;
3395 break;
3396 default:
3397 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3398 csi.fs.fsCsb[0] = 0;
3399 break;
3403 family = NULL;
3404 if(lf.lfFaceName[0] != '\0') {
3405 SYSTEM_LINKS *font_link;
3406 CHILD_FONT *font_link_entry;
3407 LPWSTR FaceName = lf.lfFaceName;
3410 * Check for a leading '@' this signals that the font is being
3411 * requested in tategaki mode (vertical writing substitution) but
3412 * does not affect the fontface that is to be selected.
3414 if (lf.lfFaceName[0]=='@')
3415 FaceName = &lf.lfFaceName[1];
3417 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3419 if(psub) {
3420 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3421 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3422 if (psub->to.charset != -1)
3423 lf.lfCharSet = psub->to.charset;
3426 /* We want a match on name and charset or just name if
3427 charset was DEFAULT_CHARSET. If the latter then
3428 we fixup the returned charset later in get_nearest_charset
3429 where we'll either use the charset of the current ansi codepage
3430 or if that's unavailable the first charset that the font supports.
3432 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3433 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3434 if (!strcmpiW(family->FamilyName, FaceName) ||
3435 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3437 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3438 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3439 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3440 if(face->scalable || can_use_bitmap)
3441 goto found;
3447 * Try check the SystemLink list first for a replacement font.
3448 * We may find good replacements there.
3450 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3452 if(!strcmpiW(font_link->font_name, FaceName) ||
3453 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3455 TRACE("found entry in system list\n");
3456 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3458 face = font_link_entry->face;
3459 family = face->family;
3460 if(csi.fs.fsCsb[0] &
3461 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3463 if(face->scalable || can_use_bitmap)
3464 goto found;
3471 psub = NULL; /* substitution is no more relevant */
3473 /* If requested charset was DEFAULT_CHARSET then try using charset
3474 corresponding to the current ansi codepage */
3475 if (!csi.fs.fsCsb[0])
3477 INT acp = GetACP();
3478 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3479 FIXME("TCI failed on codepage %d\n", acp);
3480 csi.fs.fsCsb[0] = 0;
3481 } else
3482 lf.lfCharSet = csi.ciCharset;
3485 /* Face families are in the top 4 bits of lfPitchAndFamily,
3486 so mask with 0xF0 before testing */
3488 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3489 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3490 strcpyW(lf.lfFaceName, defFixed);
3491 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3492 strcpyW(lf.lfFaceName, defSerif);
3493 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3494 strcpyW(lf.lfFaceName, defSans);
3495 else
3496 strcpyW(lf.lfFaceName, defSans);
3497 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3498 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3499 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3500 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3501 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3502 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3503 if(face->scalable || can_use_bitmap)
3504 goto found;
3509 last_resort_family = NULL;
3510 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3511 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3512 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3513 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3514 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3515 if(face->scalable)
3516 goto found;
3517 if(can_use_bitmap && !last_resort_family)
3518 last_resort_family = family;
3523 if(last_resort_family) {
3524 family = last_resort_family;
3525 csi.fs.fsCsb[0] = 0;
3526 goto found;
3529 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3530 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3531 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3532 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3533 if(face->scalable) {
3534 csi.fs.fsCsb[0] = 0;
3535 WARN("just using first face for now\n");
3536 goto found;
3538 if(can_use_bitmap && !last_resort_family)
3539 last_resort_family = family;
3542 if(!last_resort_family) {
3543 FIXME("can't find a single appropriate font - bailing\n");
3544 free_font(ret);
3545 LeaveCriticalSection( &freetype_cs );
3546 return NULL;
3549 WARN("could only find a bitmap font - this will probably look awful!\n");
3550 family = last_resort_family;
3551 csi.fs.fsCsb[0] = 0;
3553 found:
3554 it = lf.lfItalic ? 1 : 0;
3555 bd = lf.lfWeight > 550 ? 1 : 0;
3557 height = lf.lfHeight;
3559 face = best = best_bitmap = NULL;
3560 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3562 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3564 BOOL italic, bold;
3566 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3567 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3568 new_score = (italic ^ it) + (bold ^ bd);
3569 if(!best || new_score <= score)
3571 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3572 italic, bold, it, bd);
3573 score = new_score;
3574 best = face;
3575 if(best->scalable && score == 0) break;
3576 if(!best->scalable)
3578 if(height > 0)
3579 newdiff = height - (signed int)(best->size.height);
3580 else
3581 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3582 if(!best_bitmap || new_score < score ||
3583 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3585 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3586 diff = newdiff;
3587 best_bitmap = best;
3588 if(score == 0 && diff == 0) break;
3594 if(best)
3595 face = best->scalable ? best : best_bitmap;
3596 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3597 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3599 ret->fs = face->fs;
3601 if(csi.fs.fsCsb[0]) {
3602 ret->charset = lf.lfCharSet;
3603 ret->codepage = csi.ciACP;
3605 else
3606 ret->charset = get_nearest_charset(face, &ret->codepage);
3608 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3609 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3611 ret->aveWidth = height ? lf.lfWidth : 0;
3613 if(!face->scalable) {
3614 /* Windows uses integer scaling factors for bitmap fonts */
3615 INT scale, scaled_height;
3617 /* FIXME: rotation of bitmap fonts is ignored */
3618 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3619 if (ret->aveWidth)
3620 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3621 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3623 if (height != 0) height = diff;
3624 height += face->size.height;
3626 scale = (height + face->size.height - 1) / face->size.height;
3627 scaled_height = scale * face->size.height;
3628 /* Only jump to the next height if the difference <= 25% original height */
3629 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3630 /* The jump between unscaled and doubled is delayed by 1 */
3631 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3632 ret->scale_y = scale;
3634 width = face->size.x_ppem >> 6;
3635 height = face->size.y_ppem >> 6;
3637 else
3638 ret->scale_y = 1.0;
3639 TRACE("font scale y: %f\n", ret->scale_y);
3641 ret->ft_face = OpenFontFace(ret, face, width, height);
3643 if (!ret->ft_face)
3645 free_font( ret );
3646 LeaveCriticalSection( &freetype_cs );
3647 return 0;
3650 ret->ntmFlags = face->ntmFlags;
3652 if (ret->charset == SYMBOL_CHARSET &&
3653 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3654 /* No ops */
3656 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3657 /* No ops */
3659 else {
3660 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3663 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3664 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3665 ret->underline = lf.lfUnderline ? 0xff : 0;
3666 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3667 create_child_font_list(ret);
3669 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3671 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3672 if (length != GDI_ERROR)
3674 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3675 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3676 TRACE("Loaded GSUB table of %i bytes\n",length);
3680 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3682 add_to_cache(ret);
3683 LeaveCriticalSection( &freetype_cs );
3684 return ret;
3687 static void dump_gdi_font_list(void)
3689 GdiFont *gdiFont;
3690 struct list *elem_ptr;
3692 TRACE("---------- gdiFont Cache ----------\n");
3693 LIST_FOR_EACH(elem_ptr, &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);
3699 TRACE("---------- Unused gdiFont Cache ----------\n");
3700 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3701 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3702 TRACE("gdiFont=%p %s %d\n",
3703 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3707 /*************************************************************
3708 * WineEngDestroyFontInstance
3710 * free the gdiFont associated with this handle
3713 BOOL WineEngDestroyFontInstance(HFONT handle)
3715 GdiFont *gdiFont;
3716 HFONTLIST *hflist;
3717 BOOL ret = FALSE;
3718 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3719 int i = 0;
3721 GDI_CheckNotLock();
3722 EnterCriticalSection( &freetype_cs );
3724 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3726 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3727 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3728 if(hflist->hfont == handle)
3730 TRACE("removing child font %p from child list\n", gdiFont);
3731 list_remove(&gdiFont->entry);
3732 LeaveCriticalSection( &freetype_cs );
3733 return TRUE;
3737 TRACE("destroying hfont=%p\n", handle);
3738 if(TRACE_ON(font))
3739 dump_gdi_font_list();
3741 font_elem_ptr = list_head(&gdi_font_list);
3742 while(font_elem_ptr) {
3743 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3744 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3746 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3747 while(hfontlist_elem_ptr) {
3748 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3749 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3750 if(hflist->hfont == handle) {
3751 list_remove(&hflist->entry);
3752 HeapFree(GetProcessHeap(), 0, hflist);
3753 ret = TRUE;
3756 if(list_empty(&gdiFont->hfontlist)) {
3757 TRACE("Moving to Unused list\n");
3758 list_remove(&gdiFont->entry);
3759 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3764 font_elem_ptr = list_head(&unused_gdi_font_list);
3765 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3766 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3767 while(font_elem_ptr) {
3768 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3769 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3770 TRACE("freeing %p\n", gdiFont);
3771 list_remove(&gdiFont->entry);
3772 free_font(gdiFont);
3774 LeaveCriticalSection( &freetype_cs );
3775 return ret;
3778 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3779 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3781 GdiFont *font;
3782 LONG width, height;
3784 if (face->cached_enum_data)
3786 TRACE("Cached\n");
3787 *pelf = face->cached_enum_data->elf;
3788 *pntm = face->cached_enum_data->ntm;
3789 *ptype = face->cached_enum_data->type;
3790 return;
3793 font = alloc_font();
3795 if(face->scalable) {
3796 height = -2048; /* 2048 is the most common em size */
3797 width = 0;
3798 } else {
3799 height = face->size.y_ppem >> 6;
3800 width = face->size.x_ppem >> 6;
3802 font->scale_y = 1.0;
3804 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3806 free_font(font);
3807 return;
3810 font->name = strdupW(face->family->FamilyName);
3811 font->ntmFlags = face->ntmFlags;
3813 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3815 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3817 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3819 lstrcpynW(pelf->elfLogFont.lfFaceName,
3820 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3821 LF_FACESIZE);
3822 lstrcpynW(pelf->elfFullName,
3823 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3824 LF_FULLFACESIZE);
3825 lstrcpynW(pelf->elfStyle,
3826 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3827 LF_FACESIZE);
3829 else
3831 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3833 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3835 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3836 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3837 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3840 pntm->ntmTm.ntmFlags = face->ntmFlags;
3841 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3842 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3843 pntm->ntmFontSig = face->fs;
3845 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3847 pelf->elfLogFont.lfEscapement = 0;
3848 pelf->elfLogFont.lfOrientation = 0;
3849 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3850 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3851 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3852 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3853 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3854 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3855 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3856 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3857 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3858 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3859 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3861 *ptype = 0;
3862 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3863 *ptype |= TRUETYPE_FONTTYPE;
3864 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3865 *ptype |= DEVICE_FONTTYPE;
3866 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3867 *ptype |= RASTER_FONTTYPE;
3869 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3870 if (face->cached_enum_data)
3872 face->cached_enum_data->elf = *pelf;
3873 face->cached_enum_data->ntm = *pntm;
3874 face->cached_enum_data->type = *ptype;
3877 free_font(font);
3880 /*************************************************************
3881 * WineEngEnumFonts
3884 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3886 Family *family;
3887 Face *face;
3888 struct list *family_elem_ptr, *face_elem_ptr;
3889 ENUMLOGFONTEXW elf;
3890 NEWTEXTMETRICEXW ntm;
3891 DWORD type;
3892 FONTSIGNATURE fs;
3893 CHARSETINFO csi;
3894 LOGFONTW lf;
3895 int i;
3897 if (!plf)
3899 lf.lfCharSet = DEFAULT_CHARSET;
3900 lf.lfPitchAndFamily = 0;
3901 lf.lfFaceName[0] = 0;
3902 plf = &lf;
3905 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3907 GDI_CheckNotLock();
3908 EnterCriticalSection( &freetype_cs );
3909 if(plf->lfFaceName[0]) {
3910 FontSubst *psub;
3911 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3913 if(psub) {
3914 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3915 debugstr_w(psub->to.name));
3916 lf = *plf;
3917 strcpyW(lf.lfFaceName, psub->to.name);
3918 plf = &lf;
3921 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3922 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3923 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3924 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3925 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3926 GetEnumStructs(face, &elf, &ntm, &type);
3927 for(i = 0; i < 32; i++) {
3928 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3929 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3930 strcpyW(elf.elfScript, OEM_DOSW);
3931 i = 32; /* break out of loop */
3932 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3933 continue;
3934 else {
3935 fs.fsCsb[0] = 1L << i;
3936 fs.fsCsb[1] = 0;
3937 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3938 TCI_SRCFONTSIG))
3939 csi.ciCharset = DEFAULT_CHARSET;
3940 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3941 if(csi.ciCharset != DEFAULT_CHARSET) {
3942 elf.elfLogFont.lfCharSet =
3943 ntm.ntmTm.tmCharSet = csi.ciCharset;
3944 if(ElfScriptsW[i])
3945 strcpyW(elf.elfScript, ElfScriptsW[i]);
3946 else
3947 FIXME("Unknown elfscript for bit %d\n", i);
3950 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3951 debugstr_w(elf.elfLogFont.lfFaceName),
3952 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3953 csi.ciCharset, type, debugstr_w(elf.elfScript),
3954 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3955 ntm.ntmTm.ntmFlags);
3956 /* release section before callback (FIXME) */
3957 LeaveCriticalSection( &freetype_cs );
3958 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3959 EnterCriticalSection( &freetype_cs );
3964 } else {
3965 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3966 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3967 face_elem_ptr = list_head(&family->faces);
3968 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3969 GetEnumStructs(face, &elf, &ntm, &type);
3970 for(i = 0; i < 32; i++) {
3971 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3972 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3973 strcpyW(elf.elfScript, OEM_DOSW);
3974 i = 32; /* break out of loop */
3975 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3976 continue;
3977 else {
3978 fs.fsCsb[0] = 1L << i;
3979 fs.fsCsb[1] = 0;
3980 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3981 TCI_SRCFONTSIG))
3982 csi.ciCharset = DEFAULT_CHARSET;
3983 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3984 if(csi.ciCharset != DEFAULT_CHARSET) {
3985 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3986 csi.ciCharset;
3987 if(ElfScriptsW[i])
3988 strcpyW(elf.elfScript, ElfScriptsW[i]);
3989 else
3990 FIXME("Unknown elfscript for bit %d\n", i);
3993 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3994 debugstr_w(elf.elfLogFont.lfFaceName),
3995 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3996 csi.ciCharset, type, debugstr_w(elf.elfScript),
3997 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3998 ntm.ntmTm.ntmFlags);
3999 /* release section before callback (FIXME) */
4000 LeaveCriticalSection( &freetype_cs );
4001 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4002 EnterCriticalSection( &freetype_cs );
4006 LeaveCriticalSection( &freetype_cs );
4007 return 1;
4010 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4012 pt->x.value = vec->x >> 6;
4013 pt->x.fract = (vec->x & 0x3f) << 10;
4014 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4015 pt->y.value = vec->y >> 6;
4016 pt->y.fract = (vec->y & 0x3f) << 10;
4017 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4018 return;
4021 /***************************************************
4022 * According to the MSDN documentation on WideCharToMultiByte,
4023 * certain codepages cannot set the default_used parameter.
4024 * This returns TRUE if the codepage can set that parameter, false else
4025 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4027 static BOOL codepage_sets_default_used(UINT codepage)
4029 switch (codepage)
4031 case CP_UTF7:
4032 case CP_UTF8:
4033 case CP_SYMBOL:
4034 return FALSE;
4035 default:
4036 return TRUE;
4041 * GSUB Table handling functions
4044 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4046 const GSUB_CoverageFormat1* cf1;
4048 cf1 = table;
4050 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4052 int count = GET_BE_WORD(cf1->GlyphCount);
4053 int i;
4054 TRACE("Coverage Format 1, %i glyphs\n",count);
4055 for (i = 0; i < count; i++)
4056 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4057 return i;
4058 return -1;
4060 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4062 const GSUB_CoverageFormat2* cf2;
4063 int i;
4064 int count;
4065 cf2 = (GSUB_CoverageFormat2*)cf1;
4067 count = GET_BE_WORD(cf2->RangeCount);
4068 TRACE("Coverage Format 2, %i ranges\n",count);
4069 for (i = 0; i < count; i++)
4071 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4072 return -1;
4073 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4074 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4076 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4077 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4080 return -1;
4082 else
4083 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4085 return -1;
4088 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4090 const GSUB_ScriptList *script;
4091 const GSUB_Script *deflt = NULL;
4092 int i;
4093 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4095 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4096 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4098 const GSUB_Script *scr;
4099 int offset;
4101 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4102 scr = (GSUB_Script*)((LPBYTE)script + offset);
4104 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4105 return scr;
4106 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4107 deflt = scr;
4109 return deflt;
4112 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4114 int i;
4115 int offset;
4116 const GSUB_LangSys *Lang;
4118 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4120 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4122 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4123 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4125 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4126 return Lang;
4128 offset = GET_BE_WORD(script->DefaultLangSys);
4129 if (offset)
4131 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4132 return Lang;
4134 return NULL;
4137 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4139 int i;
4140 const GSUB_FeatureList *feature;
4141 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4143 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4144 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4146 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4147 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4149 const GSUB_Feature *feat;
4150 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4151 return feat;
4154 return NULL;
4157 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4159 int i;
4160 int offset;
4161 const GSUB_LookupList *lookup;
4162 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4164 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4165 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4167 const GSUB_LookupTable *look;
4168 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4169 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4170 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4171 if (GET_BE_WORD(look->LookupType) != 1)
4172 FIXME("We only handle SubType 1\n");
4173 else
4175 int j;
4177 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4179 const GSUB_SingleSubstFormat1 *ssf1;
4180 offset = GET_BE_WORD(look->SubTable[j]);
4181 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4182 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4184 int offset = GET_BE_WORD(ssf1->Coverage);
4185 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4186 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4188 TRACE(" Glyph 0x%x ->",glyph);
4189 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4190 TRACE(" 0x%x\n",glyph);
4193 else
4195 const GSUB_SingleSubstFormat2 *ssf2;
4196 INT index;
4197 INT offset;
4199 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4200 offset = GET_BE_WORD(ssf1->Coverage);
4201 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4202 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4203 TRACE(" Coverage index %i\n",index);
4204 if (index != -1)
4206 TRACE(" Glyph is 0x%x ->",glyph);
4207 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4208 TRACE("0x%x\n",glyph);
4214 return glyph;
4217 static const char* get_opentype_script(const GdiFont *font)
4220 * I am not sure if this is the correct way to generate our script tag
4223 switch (font->charset)
4225 case ANSI_CHARSET: return "latn";
4226 case BALTIC_CHARSET: return "latn"; /* ?? */
4227 case CHINESEBIG5_CHARSET: return "hani";
4228 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4229 case GB2312_CHARSET: return "hani";
4230 case GREEK_CHARSET: return "grek";
4231 case HANGUL_CHARSET: return "hang";
4232 case RUSSIAN_CHARSET: return "cyrl";
4233 case SHIFTJIS_CHARSET: return "kana";
4234 case TURKISH_CHARSET: return "latn"; /* ?? */
4235 case VIETNAMESE_CHARSET: return "latn";
4236 case JOHAB_CHARSET: return "latn"; /* ?? */
4237 case ARABIC_CHARSET: return "arab";
4238 case HEBREW_CHARSET: return "hebr";
4239 case THAI_CHARSET: return "thai";
4240 default: return "latn";
4244 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4246 const GSUB_Header *header;
4247 const GSUB_Script *script;
4248 const GSUB_LangSys *language;
4249 const GSUB_Feature *feature;
4251 if (!font->GSUB_Table)
4252 return glyph;
4254 header = font->GSUB_Table;
4256 script = GSUB_get_script_table(header, get_opentype_script(font));
4257 if (!script)
4259 TRACE("Script not found\n");
4260 return glyph;
4262 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4263 if (!language)
4265 TRACE("Language not found\n");
4266 return glyph;
4268 feature = GSUB_get_feature(header, language, "vrt2");
4269 if (!feature)
4270 feature = GSUB_get_feature(header, language, "vert");
4271 if (!feature)
4273 TRACE("vrt2/vert feature not found\n");
4274 return glyph;
4276 return GSUB_apply_feature(header, feature, glyph);
4279 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4281 FT_UInt glyphId;
4283 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4284 WCHAR wc = (WCHAR)glyph;
4285 BOOL default_used;
4286 BOOL *default_used_pointer;
4287 FT_UInt ret;
4288 char buf;
4289 default_used_pointer = NULL;
4290 default_used = FALSE;
4291 if (codepage_sets_default_used(font->codepage))
4292 default_used_pointer = &default_used;
4293 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4294 ret = 0;
4295 else
4296 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4297 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4298 return get_GSUB_vert_glyph(font,ret);
4301 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4302 glyph = glyph + 0xf000;
4303 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4304 return get_GSUB_vert_glyph(font,glyphId);
4307 /*************************************************************
4308 * WineEngGetGlyphIndices
4311 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4312 LPWORD pgi, DWORD flags)
4314 int i;
4315 int default_char = -1;
4317 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4319 for(i = 0; i < count; i++)
4321 pgi[i] = get_glyph_index(font, lpstr[i]);
4322 if (pgi[i] == 0)
4324 if (default_char == -1)
4326 if (FT_IS_SFNT(font->ft_face))
4328 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4329 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4331 else
4333 TEXTMETRICW textm;
4334 WineEngGetTextMetrics(font, &textm);
4335 default_char = textm.tmDefaultChar;
4338 pgi[i] = default_char;
4341 return count;
4344 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4346 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4347 return !memcmp(matrix, &identity, sizeof(FMAT2));
4350 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4352 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4353 return !memcmp(matrix, &identity, sizeof(MAT2));
4356 /*************************************************************
4357 * WineEngGetGlyphOutline
4359 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4360 * except that the first parameter is the HWINEENGFONT of the font in
4361 * question rather than an HDC.
4364 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4365 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4366 const MAT2* lpmat)
4368 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4369 FT_Face ft_face = incoming_font->ft_face;
4370 GdiFont *font = incoming_font;
4371 FT_UInt glyph_index;
4372 DWORD width, height, pitch, needed = 0;
4373 FT_Bitmap ft_bitmap;
4374 FT_Error err;
4375 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4376 FT_Angle angle = 0;
4377 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4378 double widthRatio = 1.0;
4379 FT_Matrix transMat = identityMat;
4380 FT_Matrix transMatUnrotated;
4381 BOOL needsTransform = FALSE;
4382 BOOL tategaki = (font->GSUB_Table != NULL);
4383 UINT original_index;
4385 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4386 buflen, buf, lpmat);
4388 TRACE("font transform %f %f %f %f\n",
4389 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4390 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4392 GDI_CheckNotLock();
4393 EnterCriticalSection( &freetype_cs );
4395 if(format & GGO_GLYPH_INDEX) {
4396 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4397 original_index = glyph;
4398 format &= ~GGO_GLYPH_INDEX;
4399 } else {
4400 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4401 ft_face = font->ft_face;
4402 original_index = glyph_index;
4405 if(format & GGO_UNHINTED) {
4406 load_flags |= FT_LOAD_NO_HINTING;
4407 format &= ~GGO_UNHINTED;
4410 /* tategaki never appears to happen to lower glyph index */
4411 if (glyph_index < TATEGAKI_LOWER_BOUND )
4412 tategaki = FALSE;
4414 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4415 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4416 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4417 font->gmsize * sizeof(GM*));
4418 } else {
4419 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4420 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4422 *lpgm = FONT_GM(font,original_index)->gm;
4423 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4424 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4425 lpgm->gmCellIncX, lpgm->gmCellIncY);
4426 LeaveCriticalSection( &freetype_cs );
4427 return 1; /* FIXME */
4431 if (!font->gm[original_index / GM_BLOCK_SIZE])
4432 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4434 /* Scaling factor */
4435 if (font->aveWidth)
4437 TEXTMETRICW tm;
4439 WineEngGetTextMetrics(font, &tm);
4441 widthRatio = (double)font->aveWidth;
4442 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4444 else
4445 widthRatio = font->scale_y;
4447 /* Scaling transform */
4448 if (widthRatio != 1.0 || font->scale_y != 1.0)
4450 FT_Matrix scaleMat;
4451 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4452 scaleMat.xy = 0;
4453 scaleMat.yx = 0;
4454 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4456 pFT_Matrix_Multiply(&scaleMat, &transMat);
4457 needsTransform = TRUE;
4460 /* Slant transform */
4461 if (font->fake_italic) {
4462 FT_Matrix slantMat;
4464 slantMat.xx = (1 << 16);
4465 slantMat.xy = ((1 << 16) >> 2);
4466 slantMat.yx = 0;
4467 slantMat.yy = (1 << 16);
4468 pFT_Matrix_Multiply(&slantMat, &transMat);
4469 needsTransform = TRUE;
4472 /* Rotation transform */
4473 transMatUnrotated = transMat;
4474 if(font->orientation && !tategaki) {
4475 FT_Matrix rotationMat;
4476 FT_Vector vecAngle;
4477 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4478 pFT_Vector_Unit(&vecAngle, angle);
4479 rotationMat.xx = vecAngle.x;
4480 rotationMat.xy = -vecAngle.y;
4481 rotationMat.yx = -rotationMat.xy;
4482 rotationMat.yy = rotationMat.xx;
4484 pFT_Matrix_Multiply(&rotationMat, &transMat);
4485 needsTransform = TRUE;
4488 /* World transform */
4489 if (!is_identity_FMAT2(&font->font_desc.matrix))
4491 FT_Matrix worldMat;
4492 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4493 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4494 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4495 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4496 pFT_Matrix_Multiply(&worldMat, &transMat);
4497 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4498 needsTransform = TRUE;
4501 /* Extra transformation specified by caller */
4502 if (!is_identity_MAT2(lpmat))
4504 FT_Matrix extraMat;
4505 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4506 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4507 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4508 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4509 pFT_Matrix_Multiply(&extraMat, &transMat);
4510 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4511 needsTransform = TRUE;
4514 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4515 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4516 format == GGO_GRAY8_BITMAP))
4518 load_flags |= FT_LOAD_NO_BITMAP;
4521 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4523 if(err) {
4524 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4525 LeaveCriticalSection( &freetype_cs );
4526 return GDI_ERROR;
4529 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4530 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4532 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4533 lsb = left >> 6;
4534 bbx = (right - left) >> 6;
4536 if(!needsTransform) {
4537 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4538 bottom = (ft_face->glyph->metrics.horiBearingY -
4539 ft_face->glyph->metrics.height) & -64;
4540 lpgm->gmCellIncX = adv;
4541 lpgm->gmCellIncY = 0;
4542 } else {
4543 INT xc, yc;
4544 FT_Vector vec;
4545 for(xc = 0; xc < 2; xc++) {
4546 for(yc = 0; yc < 2; yc++) {
4547 vec.x = (ft_face->glyph->metrics.horiBearingX +
4548 xc * ft_face->glyph->metrics.width);
4549 vec.y = ft_face->glyph->metrics.horiBearingY -
4550 yc * ft_face->glyph->metrics.height;
4551 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4552 pFT_Vector_Transform(&vec, &transMat);
4553 if(xc == 0 && yc == 0) {
4554 left = right = vec.x;
4555 top = bottom = vec.y;
4556 } else {
4557 if(vec.x < left) left = vec.x;
4558 else if(vec.x > right) right = vec.x;
4559 if(vec.y < bottom) bottom = vec.y;
4560 else if(vec.y > top) top = vec.y;
4564 left = left & -64;
4565 right = (right + 63) & -64;
4566 bottom = bottom & -64;
4567 top = (top + 63) & -64;
4569 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4570 vec.x = ft_face->glyph->metrics.horiAdvance;
4571 vec.y = 0;
4572 pFT_Vector_Transform(&vec, &transMat);
4573 lpgm->gmCellIncX = (vec.x+63) >> 6;
4574 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4576 vec.x = ft_face->glyph->metrics.horiAdvance;
4577 vec.y = 0;
4578 pFT_Vector_Transform(&vec, &transMatUnrotated);
4579 adv = (vec.x+63) >> 6;
4581 lpgm->gmBlackBoxX = (right - left) >> 6;
4582 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4583 lpgm->gmptGlyphOrigin.x = left >> 6;
4584 lpgm->gmptGlyphOrigin.y = top >> 6;
4586 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4587 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4588 lpgm->gmCellIncX, lpgm->gmCellIncY);
4590 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4591 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4593 FONT_GM(font,original_index)->gm = *lpgm;
4594 FONT_GM(font,original_index)->adv = adv;
4595 FONT_GM(font,original_index)->lsb = lsb;
4596 FONT_GM(font,original_index)->bbx = bbx;
4597 FONT_GM(font,original_index)->init = TRUE;
4600 if(format == GGO_METRICS)
4602 LeaveCriticalSection( &freetype_cs );
4603 return 1; /* FIXME */
4606 if(ft_face->glyph->format != ft_glyph_format_outline &&
4607 (format == GGO_NATIVE || format == GGO_BEZIER ||
4608 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4609 format == GGO_GRAY8_BITMAP))
4611 TRACE("loaded a bitmap\n");
4612 LeaveCriticalSection( &freetype_cs );
4613 return GDI_ERROR;
4616 switch(format) {
4617 case GGO_BITMAP:
4618 width = lpgm->gmBlackBoxX;
4619 height = lpgm->gmBlackBoxY;
4620 pitch = ((width + 31) >> 5) << 2;
4621 needed = pitch * height;
4623 if(!buf || !buflen) break;
4625 switch(ft_face->glyph->format) {
4626 case ft_glyph_format_bitmap:
4628 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4629 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4630 INT h = ft_face->glyph->bitmap.rows;
4631 while(h--) {
4632 memcpy(dst, src, w);
4633 src += ft_face->glyph->bitmap.pitch;
4634 dst += pitch;
4636 break;
4639 case ft_glyph_format_outline:
4640 ft_bitmap.width = width;
4641 ft_bitmap.rows = height;
4642 ft_bitmap.pitch = pitch;
4643 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4644 ft_bitmap.buffer = buf;
4646 if(needsTransform)
4647 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4649 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4651 /* Note: FreeType will only set 'black' bits for us. */
4652 memset(buf, 0, needed);
4653 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4654 break;
4656 default:
4657 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4658 LeaveCriticalSection( &freetype_cs );
4659 return GDI_ERROR;
4661 break;
4663 case GGO_GRAY2_BITMAP:
4664 case GGO_GRAY4_BITMAP:
4665 case GGO_GRAY8_BITMAP:
4666 case WINE_GGO_GRAY16_BITMAP:
4668 unsigned int mult, row, col;
4669 BYTE *start, *ptr;
4671 width = lpgm->gmBlackBoxX;
4672 height = lpgm->gmBlackBoxY;
4673 pitch = (width + 3) / 4 * 4;
4674 needed = pitch * height;
4676 if(!buf || !buflen) break;
4678 switch(ft_face->glyph->format) {
4679 case ft_glyph_format_bitmap:
4681 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4682 INT h = ft_face->glyph->bitmap.rows;
4683 INT x;
4684 while(h--) {
4685 for(x = 0; x < pitch; x++)
4687 if(x < ft_face->glyph->bitmap.width)
4688 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4689 else
4690 dst[x] = 0;
4692 src += ft_face->glyph->bitmap.pitch;
4693 dst += pitch;
4695 LeaveCriticalSection( &freetype_cs );
4696 return needed;
4698 case ft_glyph_format_outline:
4700 ft_bitmap.width = width;
4701 ft_bitmap.rows = height;
4702 ft_bitmap.pitch = pitch;
4703 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4704 ft_bitmap.buffer = buf;
4706 if(needsTransform)
4707 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4709 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4711 memset(ft_bitmap.buffer, 0, buflen);
4713 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4715 if(format == GGO_GRAY2_BITMAP)
4716 mult = 4;
4717 else if(format == GGO_GRAY4_BITMAP)
4718 mult = 16;
4719 else if(format == GGO_GRAY8_BITMAP)
4720 mult = 64;
4721 else /* format == WINE_GGO_GRAY16_BITMAP */
4723 LeaveCriticalSection( &freetype_cs );
4724 return needed;
4726 break;
4728 default:
4729 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4730 LeaveCriticalSection( &freetype_cs );
4731 return GDI_ERROR;
4734 start = buf;
4735 for(row = 0; row < height; row++) {
4736 ptr = start;
4737 for(col = 0; col < width; col++, ptr++) {
4738 *ptr = (((int)*ptr) * mult + 128) / 256;
4740 start += pitch;
4742 break;
4745 case WINE_GGO_HRGB_BITMAP:
4746 case WINE_GGO_HBGR_BITMAP:
4747 case WINE_GGO_VRGB_BITMAP:
4748 case WINE_GGO_VBGR_BITMAP:
4749 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4751 switch (ft_face->glyph->format)
4753 case FT_GLYPH_FORMAT_BITMAP:
4755 BYTE *src, *dst;
4756 INT src_pitch, x;
4758 width = lpgm->gmBlackBoxX;
4759 height = lpgm->gmBlackBoxY;
4760 pitch = width * 4;
4761 needed = pitch * height;
4763 if (!buf || !buflen) break;
4765 memset(buf, 0, buflen);
4766 dst = buf;
4767 src = ft_face->glyph->bitmap.buffer;
4768 src_pitch = ft_face->glyph->bitmap.pitch;
4770 while ( height-- )
4772 for (x = 0; x < width; x++)
4774 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4775 ((unsigned int *)dst)[x] = ~0u;
4777 src += src_pitch;
4778 dst += pitch;
4781 break;
4784 case FT_GLYPH_FORMAT_OUTLINE:
4786 unsigned int *dst;
4787 BYTE *src;
4788 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4789 INT x_shift, y_shift;
4790 BOOL rgb;
4791 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4792 FT_Render_Mode render_mode =
4793 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4794 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4796 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4798 if ( render_mode == FT_RENDER_MODE_LCD)
4800 lpgm->gmBlackBoxX += 2;
4801 lpgm->gmptGlyphOrigin.x -= 1;
4803 else
4805 lpgm->gmBlackBoxY += 2;
4806 lpgm->gmptGlyphOrigin.y += 1;
4810 width = lpgm->gmBlackBoxX;
4811 height = lpgm->gmBlackBoxY;
4812 pitch = width * 4;
4813 needed = pitch * height;
4815 if (!buf || !buflen) break;
4817 memset(buf, 0, buflen);
4818 dst = buf;
4819 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
4821 if ( needsTransform )
4822 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
4824 if ( pFT_Library_SetLcdFilter )
4825 pFT_Library_SetLcdFilter( library, lcdfilter );
4826 pFT_Render_Glyph (ft_face->glyph, render_mode);
4828 src = ft_face->glyph->bitmap.buffer;
4829 src_pitch = ft_face->glyph->bitmap.pitch;
4830 src_width = ft_face->glyph->bitmap.width;
4831 src_height = ft_face->glyph->bitmap.rows;
4833 if ( render_mode == FT_RENDER_MODE_LCD)
4835 rgb_interval = 1;
4836 hmul = 3;
4837 vmul = 1;
4839 else
4841 rgb_interval = src_pitch;
4842 hmul = 1;
4843 vmul = 3;
4846 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
4847 if ( x_shift < 0 ) x_shift = 0;
4848 if ( x_shift + (src_width / hmul) > width )
4849 x_shift = width - (src_width / hmul);
4851 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
4852 if ( y_shift < 0 ) y_shift = 0;
4853 if ( y_shift + (src_height / vmul) > height )
4854 y_shift = height - (src_height / vmul);
4856 dst += x_shift + y_shift * ( pitch / 4 );
4857 while ( src_height )
4859 for ( x = 0; x < src_width / hmul; x++ )
4861 if ( rgb )
4863 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
4864 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4865 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
4866 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4868 else
4870 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
4871 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4872 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
4873 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4876 src += src_pitch * vmul;
4877 dst += pitch / 4;
4878 src_height -= vmul;
4881 break;
4884 default:
4885 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
4886 LeaveCriticalSection ( &freetype_cs );
4887 return GDI_ERROR;
4890 break;
4892 #else
4893 LeaveCriticalSection( &freetype_cs );
4894 return GDI_ERROR;
4895 #endif
4897 case GGO_NATIVE:
4899 int contour, point = 0, first_pt;
4900 FT_Outline *outline = &ft_face->glyph->outline;
4901 TTPOLYGONHEADER *pph;
4902 TTPOLYCURVE *ppc;
4903 DWORD pph_start, cpfx, type;
4905 if(buflen == 0) buf = NULL;
4907 if (needsTransform && buf) {
4908 pFT_Outline_Transform(outline, &transMat);
4911 for(contour = 0; contour < outline->n_contours; contour++) {
4912 pph_start = needed;
4913 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4914 first_pt = point;
4915 if(buf) {
4916 pph->dwType = TT_POLYGON_TYPE;
4917 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4919 needed += sizeof(*pph);
4920 point++;
4921 while(point <= outline->contours[contour]) {
4922 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4923 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4924 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4925 cpfx = 0;
4926 do {
4927 if(buf)
4928 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4929 cpfx++;
4930 point++;
4931 } while(point <= outline->contours[contour] &&
4932 (outline->tags[point] & FT_Curve_Tag_On) ==
4933 (outline->tags[point-1] & FT_Curve_Tag_On));
4934 /* At the end of a contour Windows adds the start point, but
4935 only for Beziers */
4936 if(point > outline->contours[contour] &&
4937 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4938 if(buf)
4939 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4940 cpfx++;
4941 } else if(point <= outline->contours[contour] &&
4942 outline->tags[point] & FT_Curve_Tag_On) {
4943 /* add closing pt for bezier */
4944 if(buf)
4945 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4946 cpfx++;
4947 point++;
4949 if(buf) {
4950 ppc->wType = type;
4951 ppc->cpfx = cpfx;
4953 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4955 if(buf)
4956 pph->cb = needed - pph_start;
4958 break;
4960 case GGO_BEZIER:
4962 /* Convert the quadratic Beziers to cubic Beziers.
4963 The parametric eqn for a cubic Bezier is, from PLRM:
4964 r(t) = at^3 + bt^2 + ct + r0
4965 with the control points:
4966 r1 = r0 + c/3
4967 r2 = r1 + (c + b)/3
4968 r3 = r0 + c + b + a
4970 A quadratic Beizer has the form:
4971 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4973 So equating powers of t leads to:
4974 r1 = 2/3 p1 + 1/3 p0
4975 r2 = 2/3 p1 + 1/3 p2
4976 and of course r0 = p0, r3 = p2
4979 int contour, point = 0, first_pt;
4980 FT_Outline *outline = &ft_face->glyph->outline;
4981 TTPOLYGONHEADER *pph;
4982 TTPOLYCURVE *ppc;
4983 DWORD pph_start, cpfx, type;
4984 FT_Vector cubic_control[4];
4985 if(buflen == 0) buf = NULL;
4987 if (needsTransform && buf) {
4988 pFT_Outline_Transform(outline, &transMat);
4991 for(contour = 0; contour < outline->n_contours; contour++) {
4992 pph_start = needed;
4993 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4994 first_pt = point;
4995 if(buf) {
4996 pph->dwType = TT_POLYGON_TYPE;
4997 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4999 needed += sizeof(*pph);
5000 point++;
5001 while(point <= outline->contours[contour]) {
5002 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5003 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5004 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5005 cpfx = 0;
5006 do {
5007 if(type == TT_PRIM_LINE) {
5008 if(buf)
5009 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5010 cpfx++;
5011 point++;
5012 } else {
5013 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5014 so cpfx = 3n */
5016 /* FIXME: Possible optimization in endpoint calculation
5017 if there are two consecutive curves */
5018 cubic_control[0] = outline->points[point-1];
5019 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5020 cubic_control[0].x += outline->points[point].x + 1;
5021 cubic_control[0].y += outline->points[point].y + 1;
5022 cubic_control[0].x >>= 1;
5023 cubic_control[0].y >>= 1;
5025 if(point+1 > outline->contours[contour])
5026 cubic_control[3] = outline->points[first_pt];
5027 else {
5028 cubic_control[3] = outline->points[point+1];
5029 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5030 cubic_control[3].x += outline->points[point].x + 1;
5031 cubic_control[3].y += outline->points[point].y + 1;
5032 cubic_control[3].x >>= 1;
5033 cubic_control[3].y >>= 1;
5036 /* r1 = 1/3 p0 + 2/3 p1
5037 r2 = 1/3 p2 + 2/3 p1 */
5038 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5039 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5040 cubic_control[2] = cubic_control[1];
5041 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5042 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5043 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5044 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5045 if(buf) {
5046 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5047 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5048 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5050 cpfx += 3;
5051 point++;
5053 } while(point <= outline->contours[contour] &&
5054 (outline->tags[point] & FT_Curve_Tag_On) ==
5055 (outline->tags[point-1] & FT_Curve_Tag_On));
5056 /* At the end of a contour Windows adds the start point,
5057 but only for Beziers and we've already done that.
5059 if(point <= outline->contours[contour] &&
5060 outline->tags[point] & FT_Curve_Tag_On) {
5061 /* This is the closing pt of a bezier, but we've already
5062 added it, so just inc point and carry on */
5063 point++;
5065 if(buf) {
5066 ppc->wType = type;
5067 ppc->cpfx = cpfx;
5069 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5071 if(buf)
5072 pph->cb = needed - pph_start;
5074 break;
5077 default:
5078 FIXME("Unsupported format %d\n", format);
5079 LeaveCriticalSection( &freetype_cs );
5080 return GDI_ERROR;
5082 LeaveCriticalSection( &freetype_cs );
5083 return needed;
5086 static BOOL get_bitmap_text_metrics(GdiFont *font)
5088 FT_Face ft_face = font->ft_face;
5089 #ifdef HAVE_FREETYPE_FTWINFNT_H
5090 FT_WinFNT_HeaderRec winfnt_header;
5091 #endif
5092 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5093 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5094 font->potm->otmSize = size;
5096 #define TM font->potm->otmTextMetrics
5097 #ifdef HAVE_FREETYPE_FTWINFNT_H
5098 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5100 TM.tmHeight = winfnt_header.pixel_height;
5101 TM.tmAscent = winfnt_header.ascent;
5102 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5103 TM.tmInternalLeading = winfnt_header.internal_leading;
5104 TM.tmExternalLeading = winfnt_header.external_leading;
5105 TM.tmAveCharWidth = winfnt_header.avg_width;
5106 TM.tmMaxCharWidth = winfnt_header.max_width;
5107 TM.tmWeight = winfnt_header.weight;
5108 TM.tmOverhang = 0;
5109 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5110 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5111 TM.tmFirstChar = winfnt_header.first_char;
5112 TM.tmLastChar = winfnt_header.last_char;
5113 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5114 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5115 TM.tmItalic = winfnt_header.italic;
5116 TM.tmUnderlined = font->underline;
5117 TM.tmStruckOut = font->strikeout;
5118 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5119 TM.tmCharSet = winfnt_header.charset;
5121 else
5122 #endif
5124 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5125 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5126 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5127 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5128 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5129 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5130 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5131 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5132 TM.tmOverhang = 0;
5133 TM.tmDigitizedAspectX = 96; /* FIXME */
5134 TM.tmDigitizedAspectY = 96; /* FIXME */
5135 TM.tmFirstChar = 1;
5136 TM.tmLastChar = 255;
5137 TM.tmDefaultChar = 32;
5138 TM.tmBreakChar = 32;
5139 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5140 TM.tmUnderlined = font->underline;
5141 TM.tmStruckOut = font->strikeout;
5142 /* NB inverted meaning of TMPF_FIXED_PITCH */
5143 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5144 TM.tmCharSet = font->charset;
5146 #undef TM
5148 return TRUE;
5152 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5154 double scale_x, scale_y;
5156 if (font->aveWidth)
5158 scale_x = (double)font->aveWidth;
5159 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5161 else
5162 scale_x = font->scale_y;
5164 scale_x *= fabs(font->font_desc.matrix.eM11);
5165 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5167 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5168 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5170 SCALE_Y(ptm->tmHeight);
5171 SCALE_Y(ptm->tmAscent);
5172 SCALE_Y(ptm->tmDescent);
5173 SCALE_Y(ptm->tmInternalLeading);
5174 SCALE_Y(ptm->tmExternalLeading);
5175 SCALE_Y(ptm->tmOverhang);
5177 SCALE_X(ptm->tmAveCharWidth);
5178 SCALE_X(ptm->tmMaxCharWidth);
5180 #undef SCALE_X
5181 #undef SCALE_Y
5184 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5186 double scale_x, scale_y;
5188 if (font->aveWidth)
5190 scale_x = (double)font->aveWidth;
5191 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5193 else
5194 scale_x = font->scale_y;
5196 scale_x *= fabs(font->font_desc.matrix.eM11);
5197 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5199 scale_font_metrics(font, &potm->otmTextMetrics);
5201 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5202 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5204 SCALE_Y(potm->otmAscent);
5205 SCALE_Y(potm->otmDescent);
5206 SCALE_Y(potm->otmLineGap);
5207 SCALE_Y(potm->otmsCapEmHeight);
5208 SCALE_Y(potm->otmsXHeight);
5209 SCALE_Y(potm->otmrcFontBox.top);
5210 SCALE_Y(potm->otmrcFontBox.bottom);
5211 SCALE_X(potm->otmrcFontBox.left);
5212 SCALE_X(potm->otmrcFontBox.right);
5213 SCALE_Y(potm->otmMacAscent);
5214 SCALE_Y(potm->otmMacDescent);
5215 SCALE_Y(potm->otmMacLineGap);
5216 SCALE_X(potm->otmptSubscriptSize.x);
5217 SCALE_Y(potm->otmptSubscriptSize.y);
5218 SCALE_X(potm->otmptSubscriptOffset.x);
5219 SCALE_Y(potm->otmptSubscriptOffset.y);
5220 SCALE_X(potm->otmptSuperscriptSize.x);
5221 SCALE_Y(potm->otmptSuperscriptSize.y);
5222 SCALE_X(potm->otmptSuperscriptOffset.x);
5223 SCALE_Y(potm->otmptSuperscriptOffset.y);
5224 SCALE_Y(potm->otmsStrikeoutSize);
5225 SCALE_Y(potm->otmsStrikeoutPosition);
5226 SCALE_Y(potm->otmsUnderscoreSize);
5227 SCALE_Y(potm->otmsUnderscorePosition);
5229 #undef SCALE_X
5230 #undef SCALE_Y
5233 /*************************************************************
5234 * WineEngGetTextMetrics
5237 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5239 GDI_CheckNotLock();
5240 EnterCriticalSection( &freetype_cs );
5241 if(!font->potm) {
5242 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5243 if(!get_bitmap_text_metrics(font))
5245 LeaveCriticalSection( &freetype_cs );
5246 return FALSE;
5249 if(!font->potm)
5251 LeaveCriticalSection( &freetype_cs );
5252 return FALSE;
5254 *ptm = font->potm->otmTextMetrics;
5255 scale_font_metrics(font, ptm);
5256 LeaveCriticalSection( &freetype_cs );
5257 return TRUE;
5260 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5262 int i;
5264 for(i = 0; i < ft_face->num_charmaps; i++)
5266 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5267 return TRUE;
5269 return FALSE;
5272 /*************************************************************
5273 * WineEngGetOutlineTextMetrics
5276 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5277 OUTLINETEXTMETRICW *potm)
5279 FT_Face ft_face = font->ft_face;
5280 UINT needed, lenfam, lensty, ret;
5281 TT_OS2 *pOS2;
5282 TT_HoriHeader *pHori;
5283 TT_Postscript *pPost;
5284 FT_Fixed x_scale, y_scale;
5285 WCHAR *family_nameW, *style_nameW;
5286 static const WCHAR spaceW[] = {' ', '\0'};
5287 char *cp;
5288 INT ascent, descent;
5290 TRACE("font=%p\n", font);
5292 if(!FT_IS_SCALABLE(ft_face))
5293 return 0;
5295 GDI_CheckNotLock();
5296 EnterCriticalSection( &freetype_cs );
5298 if(font->potm) {
5299 if(cbSize >= font->potm->otmSize)
5301 memcpy(potm, font->potm, font->potm->otmSize);
5302 scale_outline_font_metrics(font, potm);
5304 LeaveCriticalSection( &freetype_cs );
5305 return font->potm->otmSize;
5309 needed = sizeof(*potm);
5311 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5312 family_nameW = strdupW(font->name);
5314 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5315 * sizeof(WCHAR);
5316 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5317 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5318 style_nameW, lensty/sizeof(WCHAR));
5320 /* These names should be read from the TT name table */
5322 /* length of otmpFamilyName */
5323 needed += lenfam;
5325 /* length of otmpFaceName */
5326 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5327 needed += lenfam; /* just the family name */
5328 } else {
5329 needed += lenfam + lensty; /* family + " " + style */
5332 /* length of otmpStyleName */
5333 needed += lensty;
5335 /* length of otmpFullName */
5336 needed += lenfam + lensty;
5339 x_scale = ft_face->size->metrics.x_scale;
5340 y_scale = ft_face->size->metrics.y_scale;
5342 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5343 if(!pOS2) {
5344 FIXME("Can't find OS/2 table - not TT font?\n");
5345 ret = 0;
5346 goto end;
5349 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5350 if(!pHori) {
5351 FIXME("Can't find HHEA table - not TT font?\n");
5352 ret = 0;
5353 goto end;
5356 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5358 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",
5359 pOS2->usWinAscent, pOS2->usWinDescent,
5360 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5361 ft_face->ascender, ft_face->descender, ft_face->height,
5362 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5363 ft_face->bbox.yMax, ft_face->bbox.yMin);
5365 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5366 font->potm->otmSize = needed;
5368 #define TM font->potm->otmTextMetrics
5370 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5371 ascent = pHori->Ascender;
5372 descent = -pHori->Descender;
5373 } else {
5374 ascent = pOS2->usWinAscent;
5375 descent = pOS2->usWinDescent;
5378 if(font->yMax) {
5379 TM.tmAscent = font->yMax;
5380 TM.tmDescent = -font->yMin;
5381 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5382 } else {
5383 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5384 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5385 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5386 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5389 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5391 /* MSDN says:
5392 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5394 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5395 ((ascent + descent) -
5396 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5398 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5399 if (TM.tmAveCharWidth == 0) {
5400 TM.tmAveCharWidth = 1;
5402 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5403 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5404 TM.tmOverhang = 0;
5405 TM.tmDigitizedAspectX = 300;
5406 TM.tmDigitizedAspectY = 300;
5407 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5408 * symbol range to 0 - f0ff
5411 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5413 TM.tmFirstChar = 0;
5414 switch(GetACP())
5416 case 1257: /* Baltic */
5417 TM.tmLastChar = 0xf8fd;
5418 break;
5419 default:
5420 TM.tmLastChar = 0xf0ff;
5422 TM.tmBreakChar = 0x20;
5423 TM.tmDefaultChar = 0x1f;
5425 else
5427 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5428 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5430 if(pOS2->usFirstCharIndex <= 1)
5431 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5432 else if (pOS2->usFirstCharIndex > 0xff)
5433 TM.tmBreakChar = 0x20;
5434 else
5435 TM.tmBreakChar = pOS2->usFirstCharIndex;
5436 TM.tmDefaultChar = TM.tmBreakChar - 1;
5438 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5439 TM.tmUnderlined = font->underline;
5440 TM.tmStruckOut = font->strikeout;
5442 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5443 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5444 (pOS2->version == 0xFFFFU ||
5445 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5446 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5447 else
5448 TM.tmPitchAndFamily = 0;
5450 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5452 case PAN_FAMILY_SCRIPT:
5453 TM.tmPitchAndFamily |= FF_SCRIPT;
5454 break;
5456 case PAN_FAMILY_DECORATIVE:
5457 TM.tmPitchAndFamily |= FF_DECORATIVE;
5458 break;
5460 case PAN_ANY:
5461 case PAN_NO_FIT:
5462 case PAN_FAMILY_TEXT_DISPLAY:
5463 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5464 /* which is clearly not what the panose spec says. */
5465 default:
5466 if(TM.tmPitchAndFamily == 0 || /* fixed */
5467 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5468 TM.tmPitchAndFamily = FF_MODERN;
5469 else
5471 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5473 case PAN_ANY:
5474 case PAN_NO_FIT:
5475 default:
5476 TM.tmPitchAndFamily |= FF_DONTCARE;
5477 break;
5479 case PAN_SERIF_COVE:
5480 case PAN_SERIF_OBTUSE_COVE:
5481 case PAN_SERIF_SQUARE_COVE:
5482 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5483 case PAN_SERIF_SQUARE:
5484 case PAN_SERIF_THIN:
5485 case PAN_SERIF_BONE:
5486 case PAN_SERIF_EXAGGERATED:
5487 case PAN_SERIF_TRIANGLE:
5488 TM.tmPitchAndFamily |= FF_ROMAN;
5489 break;
5491 case PAN_SERIF_NORMAL_SANS:
5492 case PAN_SERIF_OBTUSE_SANS:
5493 case PAN_SERIF_PERP_SANS:
5494 case PAN_SERIF_FLARED:
5495 case PAN_SERIF_ROUNDED:
5496 TM.tmPitchAndFamily |= FF_SWISS;
5497 break;
5500 break;
5503 if(FT_IS_SCALABLE(ft_face))
5504 TM.tmPitchAndFamily |= TMPF_VECTOR;
5506 if(FT_IS_SFNT(ft_face))
5508 if (font->ntmFlags & NTM_PS_OPENTYPE)
5509 TM.tmPitchAndFamily |= TMPF_DEVICE;
5510 else
5511 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5514 TM.tmCharSet = font->charset;
5516 font->potm->otmFiller = 0;
5517 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5518 font->potm->otmfsSelection = pOS2->fsSelection;
5519 font->potm->otmfsType = pOS2->fsType;
5520 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5521 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5522 font->potm->otmItalicAngle = 0; /* POST table */
5523 font->potm->otmEMSquare = ft_face->units_per_EM;
5524 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5525 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5526 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5527 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5528 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5529 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5530 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5531 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5532 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5533 font->potm->otmMacAscent = TM.tmAscent;
5534 font->potm->otmMacDescent = -TM.tmDescent;
5535 font->potm->otmMacLineGap = font->potm->otmLineGap;
5536 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5537 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5538 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5539 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5540 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5541 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5542 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5543 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5544 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5545 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5546 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5547 if(!pPost) {
5548 font->potm->otmsUnderscoreSize = 0;
5549 font->potm->otmsUnderscorePosition = 0;
5550 } else {
5551 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5552 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5554 #undef TM
5556 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5557 cp = (char*)font->potm + sizeof(*font->potm);
5558 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5559 strcpyW((WCHAR*)cp, family_nameW);
5560 cp += lenfam;
5561 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5562 strcpyW((WCHAR*)cp, style_nameW);
5563 cp += lensty;
5564 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5565 strcpyW((WCHAR*)cp, family_nameW);
5566 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5567 strcatW((WCHAR*)cp, spaceW);
5568 strcatW((WCHAR*)cp, style_nameW);
5569 cp += lenfam + lensty;
5570 } else
5571 cp += lenfam;
5572 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5573 strcpyW((WCHAR*)cp, family_nameW);
5574 strcatW((WCHAR*)cp, spaceW);
5575 strcatW((WCHAR*)cp, style_nameW);
5576 ret = needed;
5578 if(potm && needed <= cbSize)
5580 memcpy(potm, font->potm, font->potm->otmSize);
5581 scale_outline_font_metrics(font, potm);
5584 end:
5585 HeapFree(GetProcessHeap(), 0, style_nameW);
5586 HeapFree(GetProcessHeap(), 0, family_nameW);
5588 LeaveCriticalSection( &freetype_cs );
5589 return ret;
5592 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5594 HFONTLIST *hfontlist;
5595 child->font = alloc_font();
5596 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5597 if(!child->font->ft_face)
5599 free_font(child->font);
5600 child->font = NULL;
5601 return FALSE;
5604 child->font->font_desc = font->font_desc;
5605 child->font->ntmFlags = child->face->ntmFlags;
5606 child->font->orientation = font->orientation;
5607 child->font->scale_y = font->scale_y;
5608 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5609 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5610 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5611 child->font->base_font = font;
5612 list_add_head(&child_font_list, &child->font->entry);
5613 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5614 return TRUE;
5617 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5619 FT_UInt g;
5620 CHILD_FONT *child_font;
5622 if(font->base_font)
5623 font = font->base_font;
5625 *linked_font = font;
5627 if((*glyph = get_glyph_index(font, c)))
5628 return TRUE;
5630 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5632 if(!child_font->font)
5633 if(!load_child_font(font, child_font))
5634 continue;
5636 if(!child_font->font->ft_face)
5637 continue;
5638 g = get_glyph_index(child_font->font, c);
5639 if(g)
5641 *glyph = g;
5642 *linked_font = child_font->font;
5643 return TRUE;
5646 return FALSE;
5649 /*************************************************************
5650 * WineEngGetCharWidth
5653 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5654 LPINT buffer)
5656 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5657 UINT c;
5658 GLYPHMETRICS gm;
5659 FT_UInt glyph_index;
5660 GdiFont *linked_font;
5662 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5664 GDI_CheckNotLock();
5665 EnterCriticalSection( &freetype_cs );
5666 for(c = firstChar; c <= lastChar; c++) {
5667 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5668 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5669 &gm, 0, NULL, &identity);
5670 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5672 LeaveCriticalSection( &freetype_cs );
5673 return TRUE;
5676 /*************************************************************
5677 * WineEngGetCharABCWidths
5680 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5681 LPABC buffer)
5683 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5684 UINT c;
5685 GLYPHMETRICS gm;
5686 FT_UInt glyph_index;
5687 GdiFont *linked_font;
5689 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5691 if(!FT_IS_SCALABLE(font->ft_face))
5692 return FALSE;
5694 GDI_CheckNotLock();
5695 EnterCriticalSection( &freetype_cs );
5697 for(c = firstChar; c <= lastChar; c++) {
5698 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5699 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5700 &gm, 0, NULL, &identity);
5701 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5702 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5703 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5704 FONT_GM(linked_font,glyph_index)->bbx;
5706 LeaveCriticalSection( &freetype_cs );
5707 return TRUE;
5710 /*************************************************************
5711 * WineEngGetCharABCWidthsI
5714 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5715 LPABC buffer)
5717 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5718 UINT c;
5719 GLYPHMETRICS gm;
5720 FT_UInt glyph_index;
5721 GdiFont *linked_font;
5723 if(!FT_HAS_HORIZONTAL(font->ft_face))
5724 return FALSE;
5726 GDI_CheckNotLock();
5727 EnterCriticalSection( &freetype_cs );
5729 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5730 if (!pgi)
5731 for(c = firstChar; c < firstChar+count; c++) {
5732 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5733 &gm, 0, NULL, &identity);
5734 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5735 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5736 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5737 - FONT_GM(linked_font,c)->bbx;
5739 else
5740 for(c = 0; c < count; c++) {
5741 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5742 &gm, 0, NULL, &identity);
5743 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5744 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5745 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5746 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5749 LeaveCriticalSection( &freetype_cs );
5750 return TRUE;
5753 /*************************************************************
5754 * WineEngGetTextExtentExPoint
5757 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5758 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5760 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5761 INT idx;
5762 INT nfit = 0, ext;
5763 GLYPHMETRICS gm;
5764 TEXTMETRICW tm;
5765 FT_UInt glyph_index;
5766 GdiFont *linked_font;
5768 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5769 max_ext, size);
5771 GDI_CheckNotLock();
5772 EnterCriticalSection( &freetype_cs );
5774 size->cx = 0;
5775 WineEngGetTextMetrics(font, &tm);
5776 size->cy = tm.tmHeight;
5778 for(idx = 0; idx < count; idx++) {
5779 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5780 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5781 &gm, 0, NULL, &identity);
5782 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5783 ext = size->cx;
5784 if (! pnfit || ext <= max_ext) {
5785 ++nfit;
5786 if (dxs)
5787 dxs[idx] = ext;
5791 if (pnfit)
5792 *pnfit = nfit;
5794 LeaveCriticalSection( &freetype_cs );
5795 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5796 return TRUE;
5799 /*************************************************************
5800 * WineEngGetTextExtentExPointI
5803 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5804 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5806 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5807 INT idx;
5808 INT nfit = 0, ext;
5809 GLYPHMETRICS gm;
5810 TEXTMETRICW tm;
5812 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5814 GDI_CheckNotLock();
5815 EnterCriticalSection( &freetype_cs );
5817 size->cx = 0;
5818 WineEngGetTextMetrics(font, &tm);
5819 size->cy = tm.tmHeight;
5821 for(idx = 0; idx < count; idx++) {
5822 WineEngGetGlyphOutline(font, indices[idx],
5823 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5824 &identity);
5825 size->cx += FONT_GM(font,indices[idx])->adv;
5826 ext = size->cx;
5827 if (! pnfit || ext <= max_ext) {
5828 ++nfit;
5829 if (dxs)
5830 dxs[idx] = ext;
5834 if (pnfit)
5835 *pnfit = nfit;
5837 LeaveCriticalSection( &freetype_cs );
5838 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5839 return TRUE;
5842 /*************************************************************
5843 * WineEngGetFontData
5846 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5847 DWORD cbData)
5849 FT_Face ft_face = font->ft_face;
5850 FT_ULong len;
5851 FT_Error err;
5853 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5854 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5855 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5857 if(!FT_IS_SFNT(ft_face))
5858 return GDI_ERROR;
5860 if(!buf || !cbData)
5861 len = 0;
5862 else
5863 len = cbData;
5865 if(table) { /* MS tags differ in endianness from FT ones */
5866 table = table >> 24 | table << 24 |
5867 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5870 /* make sure value of len is the value freetype says it needs */
5871 if(buf && len)
5873 FT_ULong needed = 0;
5874 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5875 if( !err && needed < len) len = needed;
5877 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5879 if(err) {
5880 TRACE("Can't find table %c%c%c%c\n",
5881 /* bytes were reversed */
5882 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5883 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5884 return GDI_ERROR;
5886 return len;
5889 /*************************************************************
5890 * WineEngGetTextFace
5893 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5895 INT n = strlenW(font->name) + 1;
5896 if(str) {
5897 lstrcpynW(str, font->name, count);
5898 return min(count, n);
5899 } else
5900 return n;
5903 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5905 if (fs) *fs = font->fs;
5906 return font->charset;
5909 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5911 GdiFont *font = dc->gdiFont, *linked_font;
5912 struct list *first_hfont;
5913 BOOL ret;
5915 GDI_CheckNotLock();
5916 EnterCriticalSection( &freetype_cs );
5917 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5918 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5919 if(font == linked_font)
5920 *new_hfont = dc->hFont;
5921 else
5923 first_hfont = list_head(&linked_font->hfontlist);
5924 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5926 LeaveCriticalSection( &freetype_cs );
5927 return ret;
5930 /* Retrieve a list of supported Unicode ranges for a given font.
5931 * Can be called with NULL gs to calculate the buffer size. Returns
5932 * the number of ranges found.
5934 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5936 DWORD num_ranges = 0;
5938 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5940 FT_UInt glyph_code;
5941 FT_ULong char_code, char_code_prev;
5943 glyph_code = 0;
5944 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5946 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5947 face->num_glyphs, glyph_code, char_code);
5949 if (!glyph_code) return 0;
5951 if (gs)
5953 gs->ranges[0].wcLow = (USHORT)char_code;
5954 gs->ranges[0].cGlyphs = 0;
5955 gs->cGlyphsSupported = 0;
5958 num_ranges = 1;
5959 while (glyph_code)
5961 if (char_code < char_code_prev)
5963 ERR("expected increasing char code from FT_Get_Next_Char\n");
5964 return 0;
5966 if (char_code - char_code_prev > 1)
5968 num_ranges++;
5969 if (gs)
5971 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5972 gs->ranges[num_ranges - 1].cGlyphs = 1;
5973 gs->cGlyphsSupported++;
5976 else if (gs)
5978 gs->ranges[num_ranges - 1].cGlyphs++;
5979 gs->cGlyphsSupported++;
5981 char_code_prev = char_code;
5982 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5985 else
5986 FIXME("encoding %u not supported\n", face->charmap->encoding);
5988 return num_ranges;
5991 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5993 DWORD size = 0;
5994 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5996 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5997 if (glyphset)
5999 glyphset->cbThis = size;
6000 glyphset->cRanges = num_ranges;
6002 return size;
6005 /*************************************************************
6006 * FontIsLinked
6008 BOOL WineEngFontIsLinked(GdiFont *font)
6010 BOOL ret;
6011 GDI_CheckNotLock();
6012 EnterCriticalSection( &freetype_cs );
6013 ret = !list_empty(&font->child_fonts);
6014 LeaveCriticalSection( &freetype_cs );
6015 return ret;
6018 static BOOL is_hinting_enabled(void)
6020 /* Use the >= 2.2.0 function if available */
6021 if(pFT_Get_TrueType_Engine_Type)
6023 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6024 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6026 #ifdef FT_DRIVER_HAS_HINTER
6027 else
6029 FT_Module mod;
6031 /* otherwise if we've been compiled with < 2.2.0 headers
6032 use the internal macro */
6033 mod = pFT_Get_Module(library, "truetype");
6034 if(mod && FT_DRIVER_HAS_HINTER(mod))
6035 return TRUE;
6037 #endif
6039 return FALSE;
6042 static BOOL is_subpixel_rendering_enabled( void )
6044 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6045 return pFT_Library_SetLcdFilter &&
6046 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6047 #else
6048 return FALSE;
6049 #endif
6052 /*************************************************************************
6053 * GetRasterizerCaps (GDI32.@)
6055 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6057 static int hinting = -1;
6058 static int subpixel = -1;
6060 if(hinting == -1)
6062 hinting = is_hinting_enabled();
6063 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6066 if ( subpixel == -1 )
6068 subpixel = is_subpixel_rendering_enabled();
6069 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6072 lprs->nSize = sizeof(RASTERIZER_STATUS);
6073 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6074 if ( subpixel )
6075 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6076 lprs->nLanguageID = 0;
6077 return TRUE;
6080 /*************************************************************
6081 * WineEngRealizationInfo
6083 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6085 FIXME("(%p, %p): stub!\n", font, info);
6087 info->flags = 1;
6088 if(FT_IS_SCALABLE(font->ft_face))
6089 info->flags |= 2;
6091 info->cache_num = font->cache_num;
6092 info->unknown2 = -1;
6093 return TRUE;
6096 /*************************************************************************
6097 * Kerning support for TrueType fonts
6099 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6101 struct TT_kern_table
6103 USHORT version;
6104 USHORT nTables;
6107 struct TT_kern_subtable
6109 USHORT version;
6110 USHORT length;
6111 union
6113 USHORT word;
6114 struct
6116 USHORT horizontal : 1;
6117 USHORT minimum : 1;
6118 USHORT cross_stream: 1;
6119 USHORT override : 1;
6120 USHORT reserved1 : 4;
6121 USHORT format : 8;
6122 } bits;
6123 } coverage;
6126 struct TT_format0_kern_subtable
6128 USHORT nPairs;
6129 USHORT searchRange;
6130 USHORT entrySelector;
6131 USHORT rangeShift;
6134 struct TT_kern_pair
6136 USHORT left;
6137 USHORT right;
6138 short value;
6141 static DWORD parse_format0_kern_subtable(GdiFont *font,
6142 const struct TT_format0_kern_subtable *tt_f0_ks,
6143 const USHORT *glyph_to_char,
6144 KERNINGPAIR *kern_pair, DWORD cPairs)
6146 USHORT i, nPairs;
6147 const struct TT_kern_pair *tt_kern_pair;
6149 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6151 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6153 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6154 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6155 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6157 if (!kern_pair || !cPairs)
6158 return nPairs;
6160 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6162 nPairs = min(nPairs, cPairs);
6164 for (i = 0; i < nPairs; i++)
6166 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6167 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6168 /* this algorithm appears to better match what Windows does */
6169 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6170 if (kern_pair->iKernAmount < 0)
6172 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6173 kern_pair->iKernAmount -= font->ppem;
6175 else if (kern_pair->iKernAmount > 0)
6177 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6178 kern_pair->iKernAmount += font->ppem;
6180 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6182 TRACE("left %u right %u value %d\n",
6183 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6185 kern_pair++;
6187 TRACE("copied %u entries\n", nPairs);
6188 return nPairs;
6191 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6193 DWORD length;
6194 void *buf;
6195 const struct TT_kern_table *tt_kern_table;
6196 const struct TT_kern_subtable *tt_kern_subtable;
6197 USHORT i, nTables;
6198 USHORT *glyph_to_char;
6200 GDI_CheckNotLock();
6201 EnterCriticalSection( &freetype_cs );
6202 if (font->total_kern_pairs != (DWORD)-1)
6204 if (cPairs && kern_pair)
6206 cPairs = min(cPairs, font->total_kern_pairs);
6207 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6208 LeaveCriticalSection( &freetype_cs );
6209 return cPairs;
6211 LeaveCriticalSection( &freetype_cs );
6212 return font->total_kern_pairs;
6215 font->total_kern_pairs = 0;
6217 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6219 if (length == GDI_ERROR)
6221 TRACE("no kerning data in the font\n");
6222 LeaveCriticalSection( &freetype_cs );
6223 return 0;
6226 buf = HeapAlloc(GetProcessHeap(), 0, length);
6227 if (!buf)
6229 WARN("Out of memory\n");
6230 LeaveCriticalSection( &freetype_cs );
6231 return 0;
6234 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6236 /* build a glyph index to char code map */
6237 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6238 if (!glyph_to_char)
6240 WARN("Out of memory allocating a glyph index to char code map\n");
6241 HeapFree(GetProcessHeap(), 0, buf);
6242 LeaveCriticalSection( &freetype_cs );
6243 return 0;
6246 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6248 FT_UInt glyph_code;
6249 FT_ULong char_code;
6251 glyph_code = 0;
6252 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6254 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6255 font->ft_face->num_glyphs, glyph_code, char_code);
6257 while (glyph_code)
6259 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6261 /* FIXME: This doesn't match what Windows does: it does some fancy
6262 * things with duplicate glyph index to char code mappings, while
6263 * we just avoid overriding existing entries.
6265 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6266 glyph_to_char[glyph_code] = (USHORT)char_code;
6268 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6271 else
6273 ULONG n;
6275 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6276 for (n = 0; n <= 65535; n++)
6277 glyph_to_char[n] = (USHORT)n;
6280 tt_kern_table = buf;
6281 nTables = GET_BE_WORD(tt_kern_table->nTables);
6282 TRACE("version %u, nTables %u\n",
6283 GET_BE_WORD(tt_kern_table->version), nTables);
6285 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6287 for (i = 0; i < nTables; i++)
6289 struct TT_kern_subtable tt_kern_subtable_copy;
6291 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6292 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6293 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6295 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6296 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6297 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6299 /* According to the TrueType specification this is the only format
6300 * that will be properly interpreted by Windows and OS/2
6302 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6304 DWORD new_chunk, old_total = font->total_kern_pairs;
6306 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6307 glyph_to_char, NULL, 0);
6308 font->total_kern_pairs += new_chunk;
6310 if (!font->kern_pairs)
6311 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6312 font->total_kern_pairs * sizeof(*font->kern_pairs));
6313 else
6314 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6315 font->total_kern_pairs * sizeof(*font->kern_pairs));
6317 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6318 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6320 else
6321 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6323 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6326 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6327 HeapFree(GetProcessHeap(), 0, buf);
6329 if (cPairs && kern_pair)
6331 cPairs = min(cPairs, font->total_kern_pairs);
6332 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6333 LeaveCriticalSection( &freetype_cs );
6334 return cPairs;
6336 LeaveCriticalSection( &freetype_cs );
6337 return font->total_kern_pairs;
6340 #else /* HAVE_FREETYPE */
6342 /*************************************************************************/
6344 BOOL WineEngInit(void)
6346 return FALSE;
6348 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6350 return NULL;
6352 BOOL WineEngDestroyFontInstance(HFONT hfont)
6354 return FALSE;
6357 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6359 return 1;
6362 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6363 LPWORD pgi, DWORD flags)
6365 return GDI_ERROR;
6368 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6369 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6370 const MAT2* lpmat)
6372 ERR("called but we don't have FreeType\n");
6373 return GDI_ERROR;
6376 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6378 ERR("called but we don't have FreeType\n");
6379 return FALSE;
6382 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6383 OUTLINETEXTMETRICW *potm)
6385 ERR("called but we don't have FreeType\n");
6386 return 0;
6389 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6390 LPINT buffer)
6392 ERR("called but we don't have FreeType\n");
6393 return FALSE;
6396 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6397 LPABC buffer)
6399 ERR("called but we don't have FreeType\n");
6400 return FALSE;
6403 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6404 LPABC buffer)
6406 ERR("called but we don't have FreeType\n");
6407 return FALSE;
6410 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6411 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6413 ERR("called but we don't have FreeType\n");
6414 return FALSE;
6417 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6418 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6420 ERR("called but we don't have FreeType\n");
6421 return FALSE;
6424 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6425 DWORD cbData)
6427 ERR("called but we don't have FreeType\n");
6428 return GDI_ERROR;
6431 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6433 ERR("called but we don't have FreeType\n");
6434 return 0;
6437 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6439 FIXME(":stub\n");
6440 return 1;
6443 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6445 FIXME(":stub\n");
6446 return TRUE;
6449 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6451 FIXME(":stub\n");
6452 return NULL;
6455 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6457 FIXME(":stub\n");
6458 return DEFAULT_CHARSET;
6461 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6463 return FALSE;
6466 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6468 FIXME("(%p, %p): stub\n", font, glyphset);
6469 return 0;
6472 BOOL WineEngFontIsLinked(GdiFont *font)
6474 return FALSE;
6477 /*************************************************************************
6478 * GetRasterizerCaps (GDI32.@)
6480 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6482 lprs->nSize = sizeof(RASTERIZER_STATUS);
6483 lprs->wFlags = 0;
6484 lprs->nLanguageID = 0;
6485 return TRUE;
6488 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6490 ERR("called but we don't have FreeType\n");
6491 return 0;
6494 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6496 ERR("called but we don't have FreeType\n");
6497 return FALSE;
6500 #endif /* HAVE_FREETYPE */