kernel32: Immediately return on failing to start wineboot
[wine/wine64.git] / dlls / gdi32 / freetype.c
blobd011c97c02518970e5b88af073a9141f971a8ec0
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/unicode.h"
88 #include "wine/debug.h"
89 #include "wine/list.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FREETYPE
95 #ifdef HAVE_FT2BUILD_H
96 #include <ft2build.h>
97 #endif
98 #ifdef HAVE_FREETYPE_FREETYPE_H
99 #include <freetype/freetype.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FTGLYPH_H
102 #include <freetype/ftglyph.h>
103 #endif
104 #ifdef HAVE_FREETYPE_TTTABLES_H
105 #include <freetype/tttables.h>
106 #endif
107 #ifdef HAVE_FREETYPE_FTTYPES_H
108 #include <freetype/fttypes.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTSNAMES_H
111 #include <freetype/ftsnames.h>
112 #else
113 # ifdef HAVE_FREETYPE_FTNAMES_H
114 # include <freetype/ftnames.h>
115 # endif
116 #endif
117 #ifdef HAVE_FREETYPE_TTNAMEID_H
118 #include <freetype/ttnameid.h>
119 #endif
120 #ifdef HAVE_FREETYPE_FTOUTLN_H
121 #include <freetype/ftoutln.h>
122 #endif
123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
124 #include <freetype/internal/sfnt.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTTRIGON_H
127 #include <freetype/fttrigon.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTWINFNT_H
130 #include <freetype/ftwinfnt.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTMODAPI_H
133 #include <freetype/ftmodapi.h>
134 #endif
135 #ifdef HAVE_FREETYPE_FTLCDFIL_H
136 #include <freetype/ftlcdfil.h>
137 #endif
139 #ifndef HAVE_FT_TRUETYPEENGINETYPE
140 typedef enum
142 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
143 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
144 FT_TRUETYPE_ENGINE_TYPE_PATENTED
145 } FT_TrueTypeEngineType;
146 #endif
148 static FT_Library library = 0;
149 typedef struct
151 FT_Int major;
152 FT_Int minor;
153 FT_Int patch;
154 } FT_Version_t;
155 static FT_Version_t FT_Version;
156 static DWORD FT_SimpleVersion;
158 static void *ft_handle = NULL;
160 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
161 MAKE_FUNCPTR(FT_Vector_Unit);
162 MAKE_FUNCPTR(FT_Done_Face);
163 MAKE_FUNCPTR(FT_Get_Char_Index);
164 MAKE_FUNCPTR(FT_Get_Module);
165 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
166 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
167 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
168 MAKE_FUNCPTR(FT_Init_FreeType);
169 MAKE_FUNCPTR(FT_Load_Glyph);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Select_Charmap);
182 MAKE_FUNCPTR(FT_Set_Charmap);
183 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
184 MAKE_FUNCPTR(FT_Vector_Transform);
185 MAKE_FUNCPTR(FT_Render_Glyph);
186 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
187 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
188 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
189 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
190 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
191 #ifdef HAVE_FREETYPE_FTLCDFIL_H
192 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
193 #endif
194 #ifdef HAVE_FREETYPE_FTWINFNT_H
195 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
196 #endif
198 #ifdef SONAME_LIBFONTCONFIG
199 #include <fontconfig/fontconfig.h>
200 MAKE_FUNCPTR(FcConfigGetCurrent);
201 MAKE_FUNCPTR(FcFontList);
202 MAKE_FUNCPTR(FcFontSetDestroy);
203 MAKE_FUNCPTR(FcInit);
204 MAKE_FUNCPTR(FcObjectSetAdd);
205 MAKE_FUNCPTR(FcObjectSetCreate);
206 MAKE_FUNCPTR(FcObjectSetDestroy);
207 MAKE_FUNCPTR(FcPatternCreate);
208 MAKE_FUNCPTR(FcPatternDestroy);
209 MAKE_FUNCPTR(FcPatternGetBool);
210 MAKE_FUNCPTR(FcPatternGetString);
211 #endif
213 #undef MAKE_FUNCPTR
215 #ifndef FT_MAKE_TAG
216 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
217 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
218 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
219 #endif
221 #ifndef ft_encoding_none
222 #define FT_ENCODING_NONE ft_encoding_none
223 #endif
224 #ifndef ft_encoding_ms_symbol
225 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
226 #endif
227 #ifndef ft_encoding_unicode
228 #define FT_ENCODING_UNICODE ft_encoding_unicode
229 #endif
230 #ifndef ft_encoding_apple_roman
231 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
232 #endif
234 #ifdef WORDS_BIGENDIAN
235 #define GET_BE_WORD(x) (x)
236 #else
237 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
238 #endif
240 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 typedef struct {
242 FT_Short height;
243 FT_Short width;
244 FT_Pos size;
245 FT_Pos x_ppem;
246 FT_Pos y_ppem;
247 FT_Short internal_leading;
248 } Bitmap_Size;
250 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
251 So to let this compile on older versions of FreeType we'll define the
252 new structure here. */
253 typedef struct {
254 FT_Short height, width;
255 FT_Pos size, x_ppem, y_ppem;
256 } My_FT_Bitmap_Size;
258 struct enum_data
260 ENUMLOGFONTEXW elf;
261 NEWTEXTMETRICEXW ntm;
262 DWORD type;
265 typedef struct tagFace {
266 struct list entry;
267 WCHAR *StyleName;
268 char *file;
269 void *font_data_ptr;
270 DWORD font_data_size;
271 FT_Long face_index;
272 FONTSIGNATURE fs;
273 FONTSIGNATURE fs_links;
274 DWORD ntmFlags;
275 FT_Fixed font_version;
276 BOOL scalable;
277 Bitmap_Size size; /* set if face is a bitmap */
278 BOOL external; /* TRUE if we should manually add this font to the registry */
279 struct tagFamily *family;
280 /* Cached data for Enum */
281 struct enum_data *cached_enum_data;
282 } Face;
284 typedef struct tagFamily {
285 struct list entry;
286 const WCHAR *FamilyName;
287 struct list faces;
288 } Family;
290 typedef struct {
291 GLYPHMETRICS gm;
292 INT adv; /* These three hold to widths of the unrotated chars */
293 INT lsb;
294 INT bbx;
295 BOOL init;
296 } GM;
298 typedef struct {
299 FLOAT eM11, eM12;
300 FLOAT eM21, eM22;
301 } FMAT2;
303 typedef struct {
304 DWORD hash;
305 LOGFONTW lf;
306 FMAT2 matrix;
307 BOOL can_use_bitmap;
308 } FONT_DESC;
310 typedef struct tagHFONTLIST {
311 struct list entry;
312 HFONT hfont;
313 } HFONTLIST;
315 typedef struct {
316 struct list entry;
317 Face *face;
318 GdiFont *font;
319 } CHILD_FONT;
321 struct tagGdiFont {
322 struct list entry;
323 GM **gm;
324 DWORD gmsize;
325 struct list hfontlist;
326 OUTLINETEXTMETRICW *potm;
327 DWORD total_kern_pairs;
328 KERNINGPAIR *kern_pairs;
329 struct list child_fonts;
331 /* the following members can be accessed without locking, they are never modified after creation */
332 FT_Face ft_face;
333 struct font_mapping *mapping;
334 LPWSTR name;
335 int charset;
336 int codepage;
337 BOOL fake_italic;
338 BOOL fake_bold;
339 BYTE underline;
340 BYTE strikeout;
341 INT orientation;
342 FONT_DESC font_desc;
343 LONG aveWidth, ppem;
344 double scale_y;
345 SHORT yMax;
346 SHORT yMin;
347 DWORD ntmFlags;
348 FONTSIGNATURE fs;
349 GdiFont *base_font;
350 VOID *GSUB_Table;
351 DWORD cache_num;
354 typedef struct {
355 struct list entry;
356 const WCHAR *font_name;
357 struct list links;
358 } SYSTEM_LINKS;
360 #define GM_BLOCK_SIZE 128
361 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
363 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
364 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
365 #define UNUSED_CACHE_SIZE 10
366 static struct list child_font_list = LIST_INIT(child_font_list);
367 static struct list system_links = LIST_INIT(system_links);
369 static struct list font_subst_list = LIST_INIT(font_subst_list);
371 static struct list font_list = LIST_INIT(font_list);
373 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
374 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
375 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
377 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
378 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
379 'W','i','n','d','o','w','s','\\',
380 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
381 'F','o','n','t','s','\0'};
383 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
384 'W','i','n','d','o','w','s',' ','N','T','\\',
385 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
386 'F','o','n','t','s','\0'};
388 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
389 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
390 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
391 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
393 static const WCHAR * const SystemFontValues[4] = {
394 System_Value,
395 OEMFont_Value,
396 FixedSys_Value,
397 NULL
400 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
401 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
403 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
404 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
405 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
406 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
407 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
408 'E','u','r','o','p','e','a','n','\0'};
409 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
410 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
411 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
412 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
413 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
414 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
415 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
416 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
417 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
418 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
419 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
420 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
422 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
423 WesternW, /*00*/
424 Central_EuropeanW,
425 CyrillicW,
426 GreekW,
427 TurkishW,
428 HebrewW,
429 ArabicW,
430 BalticW,
431 VietnameseW, /*08*/
432 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
433 ThaiW,
434 JapaneseW,
435 CHINESE_GB2312W,
436 HangulW,
437 CHINESE_BIG5W,
438 Hangul_Johab_W,
439 NULL, NULL, /*23*/
440 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
441 SymbolW /*31*/
444 typedef struct {
445 WCHAR *name;
446 INT charset;
447 } NameCs;
449 typedef struct tagFontSubst {
450 struct list entry;
451 NameCs from;
452 NameCs to;
453 } FontSubst;
455 struct font_mapping
457 struct list entry;
458 int refcount;
459 dev_t dev;
460 ino_t ino;
461 void *data;
462 size_t size;
465 static struct list mappings_list = LIST_INIT( mappings_list );
467 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
469 static CRITICAL_SECTION freetype_cs;
470 static CRITICAL_SECTION_DEBUG critsect_debug =
472 0, 0, &freetype_cs,
473 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
474 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
476 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
478 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
480 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
481 static BOOL use_default_fallback = FALSE;
483 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
485 /****************************************
486 * Notes on .fon files
488 * The fonts System, FixedSys and Terminal are special. There are typically multiple
489 * versions installed for different resolutions and codepages. Windows stores which one to use
490 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
491 * Key Meaning
492 * FIXEDFON.FON FixedSys
493 * FONTS.FON System
494 * OEMFONT.FON Terminal
495 * LogPixels Current dpi set by the display control panel applet
496 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
497 * also has a LogPixels value that appears to mirror this)
499 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
500 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
501 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
502 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
503 * so that makes sense.
505 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
506 * to be mapped into the registry on Windows 2000 at least).
507 * I have
508 * woafont=app850.fon
509 * ega80woa.fon=ega80850.fon
510 * ega40woa.fon=ega40850.fon
511 * cga80woa.fon=cga80850.fon
512 * cga40woa.fon=cga40850.fon
515 /* These are all structures needed for the GSUB table */
517 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
518 #define TATEGAKI_LOWER_BOUND 0x02F1
520 typedef struct {
521 DWORD version;
522 WORD ScriptList;
523 WORD FeatureList;
524 WORD LookupList;
525 } GSUB_Header;
527 typedef struct {
528 CHAR ScriptTag[4];
529 WORD Script;
530 } GSUB_ScriptRecord;
532 typedef struct {
533 WORD ScriptCount;
534 GSUB_ScriptRecord ScriptRecord[1];
535 } GSUB_ScriptList;
537 typedef struct {
538 CHAR LangSysTag[4];
539 WORD LangSys;
540 } GSUB_LangSysRecord;
542 typedef struct {
543 WORD DefaultLangSys;
544 WORD LangSysCount;
545 GSUB_LangSysRecord LangSysRecord[1];
546 } GSUB_Script;
548 typedef struct {
549 WORD LookupOrder; /* Reserved */
550 WORD ReqFeatureIndex;
551 WORD FeatureCount;
552 WORD FeatureIndex[1];
553 } GSUB_LangSys;
555 typedef struct {
556 CHAR FeatureTag[4];
557 WORD Feature;
558 } GSUB_FeatureRecord;
560 typedef struct {
561 WORD FeatureCount;
562 GSUB_FeatureRecord FeatureRecord[1];
563 } GSUB_FeatureList;
565 typedef struct {
566 WORD FeatureParams; /* Reserved */
567 WORD LookupCount;
568 WORD LookupListIndex[1];
569 } GSUB_Feature;
571 typedef struct {
572 WORD LookupCount;
573 WORD Lookup[1];
574 } GSUB_LookupList;
576 typedef struct {
577 WORD LookupType;
578 WORD LookupFlag;
579 WORD SubTableCount;
580 WORD SubTable[1];
581 } GSUB_LookupTable;
583 typedef struct {
584 WORD CoverageFormat;
585 WORD GlyphCount;
586 WORD GlyphArray[1];
587 } GSUB_CoverageFormat1;
589 typedef struct {
590 WORD Start;
591 WORD End;
592 WORD StartCoverageIndex;
593 } GSUB_RangeRecord;
595 typedef struct {
596 WORD CoverageFormat;
597 WORD RangeCount;
598 GSUB_RangeRecord RangeRecord[1];
599 } GSUB_CoverageFormat2;
601 typedef struct {
602 WORD SubstFormat; /* = 1 */
603 WORD Coverage;
604 WORD DeltaGlyphID;
605 } GSUB_SingleSubstFormat1;
607 typedef struct {
608 WORD SubstFormat; /* = 2 */
609 WORD Coverage;
610 WORD GlyphCount;
611 WORD Substitute[1];
612 }GSUB_SingleSubstFormat2;
614 #ifdef HAVE_CARBON_CARBON_H
615 static char *find_cache_dir(void)
617 FSRef ref;
618 OSErr err;
619 static char cached_path[MAX_PATH];
620 static const char *wine = "/Wine", *fonts = "/Fonts";
622 if(*cached_path) return cached_path;
624 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
625 if(err != noErr)
627 WARN("can't create cached data folder\n");
628 return NULL;
630 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
631 if(err != noErr)
633 WARN("can't create cached data path\n");
634 *cached_path = '\0';
635 return NULL;
637 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
639 ERR("Could not create full path\n");
640 *cached_path = '\0';
641 return NULL;
643 strcat(cached_path, wine);
645 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
647 WARN("Couldn't mkdir %s\n", cached_path);
648 *cached_path = '\0';
649 return NULL;
651 strcat(cached_path, fonts);
652 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
654 WARN("Couldn't mkdir %s\n", cached_path);
655 *cached_path = '\0';
656 return NULL;
658 return cached_path;
661 /******************************************************************
662 * expand_mac_font
664 * Extracts individual TrueType font files from a Mac suitcase font
665 * and saves them into the user's caches directory (see
666 * find_cache_dir()).
667 * Returns a NULL terminated array of filenames.
669 * We do this because they are apps that try to read ttf files
670 * themselves and they don't like Mac suitcase files.
672 static char **expand_mac_font(const char *path)
674 FSRef ref;
675 SInt16 res_ref;
676 OSStatus s;
677 unsigned int idx;
678 const char *out_dir;
679 const char *filename;
680 int output_len;
681 struct {
682 char **array;
683 unsigned int size, max_size;
684 } ret;
686 TRACE("path %s\n", path);
688 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
689 if(s != noErr)
691 WARN("failed to get ref\n");
692 return NULL;
695 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
696 if(s != noErr)
698 TRACE("no data fork, so trying resource fork\n");
699 res_ref = FSOpenResFile(&ref, fsRdPerm);
700 if(res_ref == -1)
702 TRACE("unable to open resource fork\n");
703 return NULL;
707 ret.size = 0;
708 ret.max_size = 10;
709 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
710 if(!ret.array)
712 CloseResFile(res_ref);
713 return NULL;
716 out_dir = find_cache_dir();
718 filename = strrchr(path, '/');
719 if(!filename) filename = path;
720 else filename++;
722 /* output filename has the form out_dir/filename_%04x.ttf */
723 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
725 UseResFile(res_ref);
726 idx = 1;
727 while(1)
729 FamRec *fam_rec;
730 unsigned short *num_faces_ptr, num_faces, face;
731 AsscEntry *assoc;
732 Handle fond;
733 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
735 fond = Get1IndResource(fond_res, idx);
736 if(!fond) break;
737 TRACE("got fond resource %d\n", idx);
738 HLock(fond);
740 fam_rec = *(FamRec**)fond;
741 num_faces_ptr = (unsigned short *)(fam_rec + 1);
742 num_faces = GET_BE_WORD(*num_faces_ptr);
743 num_faces++;
744 assoc = (AsscEntry*)(num_faces_ptr + 1);
745 TRACE("num faces %04x\n", num_faces);
746 for(face = 0; face < num_faces; face++, assoc++)
748 Handle sfnt;
749 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
750 unsigned short size, font_id;
751 char *output;
753 size = GET_BE_WORD(assoc->fontSize);
754 font_id = GET_BE_WORD(assoc->fontID);
755 if(size != 0)
757 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
758 continue;
761 TRACE("trying to load sfnt id %04x\n", font_id);
762 sfnt = GetResource(sfnt_res, font_id);
763 if(!sfnt)
765 TRACE("can't get sfnt resource %04x\n", font_id);
766 continue;
769 output = HeapAlloc(GetProcessHeap(), 0, output_len);
770 if(output)
772 int fd;
774 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
776 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
777 if(fd != -1 || errno == EEXIST)
779 if(fd != -1)
781 unsigned char *sfnt_data;
783 HLock(sfnt);
784 sfnt_data = *(unsigned char**)sfnt;
785 write(fd, sfnt_data, GetHandleSize(sfnt));
786 HUnlock(sfnt);
787 close(fd);
789 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
791 ret.max_size *= 2;
792 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
794 ret.array[ret.size++] = output;
796 else
798 WARN("unable to create %s\n", output);
799 HeapFree(GetProcessHeap(), 0, output);
802 ReleaseResource(sfnt);
804 HUnlock(fond);
805 ReleaseResource(fond);
806 idx++;
808 CloseResFile(res_ref);
810 return ret.array;
813 #endif /* HAVE_CARBON_CARBON_H */
815 static inline BOOL is_win9x(void)
817 return GetVersion() & 0x80000000;
820 This function builds an FT_Fixed from a double. It fails if the absolute
821 value of the float number is greater than 32768.
823 static inline FT_Fixed FT_FixedFromFloat(double f)
825 return f * 0x10000;
829 This function builds an FT_Fixed from a FIXED. It simply put f.value
830 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
832 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
834 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
838 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
840 Family *family;
841 Face *face;
842 const char *file;
843 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
844 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
846 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
847 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
849 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
851 if(face_name && strcmpiW(face_name, family->FamilyName))
852 continue;
853 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
855 if (!face->file)
856 continue;
857 file = strrchr(face->file, '/');
858 if(!file)
859 file = face->file;
860 else
861 file++;
862 if(!strcasecmp(file, file_nameA))
864 HeapFree(GetProcessHeap(), 0, file_nameA);
865 return face;
869 HeapFree(GetProcessHeap(), 0, file_nameA);
870 return NULL;
873 static Family *find_family_from_name(const WCHAR *name)
875 Family *family;
877 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
879 if(!strcmpiW(family->FamilyName, name))
880 return family;
883 return NULL;
886 static void DumpSubstList(void)
888 FontSubst *psub;
890 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
892 if(psub->from.charset != -1 || psub->to.charset != -1)
893 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
894 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
895 else
896 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
897 debugstr_w(psub->to.name));
899 return;
902 static LPWSTR strdupW(LPCWSTR p)
904 LPWSTR ret;
905 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
907 memcpy(ret, p, len);
908 return ret;
911 static LPSTR strdupA(LPCSTR p)
913 LPSTR ret;
914 DWORD len = (strlen(p) + 1);
915 ret = HeapAlloc(GetProcessHeap(), 0, len);
916 memcpy(ret, p, len);
917 return ret;
920 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
921 INT from_charset)
923 FontSubst *element;
925 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
927 if(!strcmpiW(element->from.name, from_name) &&
928 (element->from.charset == from_charset ||
929 element->from.charset == -1))
930 return element;
933 return NULL;
936 #define ADD_FONT_SUBST_FORCE 1
938 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
940 FontSubst *from_exist, *to_exist;
942 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
944 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
946 list_remove(&from_exist->entry);
947 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
948 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
949 HeapFree(GetProcessHeap(), 0, from_exist);
950 from_exist = NULL;
953 if(!from_exist)
955 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
957 if(to_exist)
959 HeapFree(GetProcessHeap(), 0, subst->to.name);
960 subst->to.name = strdupW(to_exist->to.name);
963 list_add_tail(subst_list, &subst->entry);
965 return TRUE;
968 HeapFree(GetProcessHeap(), 0, subst->from.name);
969 HeapFree(GetProcessHeap(), 0, subst->to.name);
970 HeapFree(GetProcessHeap(), 0, subst);
971 return FALSE;
974 static void split_subst_info(NameCs *nc, LPSTR str)
976 CHAR *p = strrchr(str, ',');
977 DWORD len;
979 nc->charset = -1;
980 if(p && *(p+1)) {
981 nc->charset = strtol(p+1, NULL, 10);
982 *p = '\0';
984 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
985 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
986 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
989 static void LoadSubstList(void)
991 FontSubst *psub;
992 HKEY hkey;
993 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
994 LPSTR value;
995 LPVOID data;
997 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
998 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
999 &hkey) == ERROR_SUCCESS) {
1001 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1002 &valuelen, &datalen, NULL, NULL);
1004 valuelen++; /* returned value doesn't include room for '\0' */
1005 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1006 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1008 dlen = datalen;
1009 vlen = valuelen;
1010 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1011 &dlen) == ERROR_SUCCESS) {
1012 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1014 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1015 split_subst_info(&psub->from, value);
1016 split_subst_info(&psub->to, data);
1018 /* Win 2000 doesn't allow mapping between different charsets
1019 or mapping of DEFAULT_CHARSET */
1020 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1021 psub->to.charset == DEFAULT_CHARSET) {
1022 HeapFree(GetProcessHeap(), 0, psub->to.name);
1023 HeapFree(GetProcessHeap(), 0, psub->from.name);
1024 HeapFree(GetProcessHeap(), 0, psub);
1025 } else {
1026 add_font_subst(&font_subst_list, psub, 0);
1028 /* reset dlen and vlen */
1029 dlen = datalen;
1030 vlen = valuelen;
1032 HeapFree(GetProcessHeap(), 0, data);
1033 HeapFree(GetProcessHeap(), 0, value);
1034 RegCloseKey(hkey);
1039 /*****************************************************************
1040 * get_name_table_entry
1042 * Supply the platform, encoding, language and name ids in req
1043 * and if the name exists the function will fill in the string
1044 * and string_len members. The string is owned by FreeType so
1045 * don't free it. Returns TRUE if the name is found else FALSE.
1047 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1049 FT_SfntName name;
1050 FT_UInt num_names, name_index;
1052 if(FT_IS_SFNT(ft_face))
1054 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1056 for(name_index = 0; name_index < num_names; name_index++)
1058 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1060 if((name.platform_id == req->platform_id) &&
1061 (name.encoding_id == req->encoding_id) &&
1062 (name.language_id == req->language_id) &&
1063 (name.name_id == req->name_id))
1065 req->string = name.string;
1066 req->string_len = name.string_len;
1067 return TRUE;
1072 req->string = NULL;
1073 req->string_len = 0;
1074 return FALSE;
1077 static WCHAR *get_familyname(FT_Face ft_face)
1079 WCHAR *family = NULL;
1080 FT_SfntName name;
1082 name.platform_id = TT_PLATFORM_MICROSOFT;
1083 name.encoding_id = TT_MS_ID_UNICODE_CS;
1084 name.language_id = GetUserDefaultLCID();
1085 name.name_id = TT_NAME_ID_FONT_FAMILY;
1087 if(get_name_table_entry(ft_face, &name))
1089 FT_UInt i;
1091 /* String is not nul terminated and string_len is a byte length. */
1092 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1093 for(i = 0; i < name.string_len / 2; i++)
1095 WORD *tmp = (WORD *)&name.string[i * 2];
1096 family[i] = GET_BE_WORD(*tmp);
1098 family[i] = 0;
1099 TRACE("Got localised name %s\n", debugstr_w(family));
1102 return family;
1106 /*****************************************************************
1107 * load_sfnt_table
1109 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1110 * of FreeType that don't export this function.
1113 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1116 FT_Error err;
1118 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1119 if(pFT_Load_Sfnt_Table)
1121 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1124 else /* Do it the hard way */
1126 TT_Face tt_face = (TT_Face) ft_face;
1127 SFNT_Interface *sfnt;
1128 if (FT_Version.major==2 && FT_Version.minor==0)
1130 /* 2.0.x */
1131 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1133 else
1135 /* A field was added in the middle of the structure in 2.1.x */
1136 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1138 err = sfnt->load_any(tt_face, table, offset, buf, len);
1140 #else
1141 else
1143 static int msg;
1144 if(!msg)
1146 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1147 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1148 "Please upgrade your freetype library.\n");
1149 msg++;
1151 err = FT_Err_Unimplemented_Feature;
1153 #endif
1154 return err;
1157 static inline int TestStyles(DWORD flags, DWORD styles)
1159 return (flags & styles) == styles;
1162 static int StyleOrdering(Face *face)
1164 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1165 return 3;
1166 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1167 return 2;
1168 if (TestStyles(face->ntmFlags, NTM_BOLD))
1169 return 1;
1170 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1171 return 0;
1173 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1174 debugstr_w(face->family->FamilyName),
1175 debugstr_w(face->StyleName),
1176 face->ntmFlags);
1178 return 9999;
1181 /* Add a style of face to a font family using an ordering of the list such
1182 that regular fonts come before bold and italic, and single styles come
1183 before compound styles. */
1184 static void AddFaceToFamily(Face *face, Family *family)
1186 struct list *entry;
1188 LIST_FOR_EACH( entry, &family->faces )
1190 Face *ent = LIST_ENTRY(entry, Face, entry);
1191 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1193 list_add_before( entry, &face->entry );
1196 #define ADDFONT_EXTERNAL_FONT 0x01
1197 #define ADDFONT_FORCE_BITMAP 0x02
1198 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1200 FT_Face ft_face;
1201 TT_OS2 *pOS2;
1202 TT_Header *pHeader = NULL;
1203 WCHAR *english_family, *localised_family, *StyleW;
1204 DWORD len;
1205 Family *family;
1206 Face *face;
1207 struct list *family_elem_ptr, *face_elem_ptr;
1208 FT_Error err;
1209 FT_Long face_index = 0, num_faces;
1210 #ifdef HAVE_FREETYPE_FTWINFNT_H
1211 FT_WinFNT_HeaderRec winfnt_header;
1212 #endif
1213 int i, bitmap_num, internal_leading;
1214 FONTSIGNATURE fs;
1216 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1217 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1219 #ifdef HAVE_CARBON_CARBON_H
1220 if(file && !fake_family)
1222 char **mac_list = expand_mac_font(file);
1223 if(mac_list)
1225 BOOL had_one = FALSE;
1226 char **cursor;
1227 for(cursor = mac_list; *cursor; cursor++)
1229 had_one = TRUE;
1230 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1231 HeapFree(GetProcessHeap(), 0, *cursor);
1233 HeapFree(GetProcessHeap(), 0, mac_list);
1234 if(had_one)
1235 return 1;
1238 #endif /* HAVE_CARBON_CARBON_H */
1240 do {
1241 char *family_name = fake_family;
1243 if (file)
1245 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1246 err = pFT_New_Face(library, file, face_index, &ft_face);
1247 } else
1249 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1250 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1253 if(err != 0) {
1254 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1255 return 0;
1258 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1259 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1260 pFT_Done_Face(ft_face);
1261 return 0;
1264 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1265 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1266 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1267 pFT_Done_Face(ft_face);
1268 return 0;
1271 if(FT_IS_SFNT(ft_face))
1273 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1274 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1275 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1277 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1278 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1279 pFT_Done_Face(ft_face);
1280 return 0;
1283 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1284 we don't want to load these. */
1285 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1287 FT_ULong len = 0;
1289 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1291 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1292 pFT_Done_Face(ft_face);
1293 return 0;
1298 if(!ft_face->family_name || !ft_face->style_name) {
1299 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1300 pFT_Done_Face(ft_face);
1301 return 0;
1304 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1306 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1307 pFT_Done_Face(ft_face);
1308 return 0;
1311 if (target_family)
1313 localised_family = get_familyname(ft_face);
1314 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1316 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1317 HeapFree(GetProcessHeap(), 0, localised_family);
1318 num_faces = ft_face->num_faces;
1319 pFT_Done_Face(ft_face);
1320 continue;
1322 HeapFree(GetProcessHeap(), 0, localised_family);
1325 if(!family_name)
1326 family_name = ft_face->family_name;
1328 bitmap_num = 0;
1329 do {
1330 My_FT_Bitmap_Size *size = NULL;
1331 FT_ULong tmp_size;
1333 if(!FT_IS_SCALABLE(ft_face))
1334 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1336 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1337 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1338 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1340 localised_family = NULL;
1341 if(!fake_family) {
1342 localised_family = get_familyname(ft_face);
1343 if(localised_family && !strcmpW(localised_family, english_family)) {
1344 HeapFree(GetProcessHeap(), 0, localised_family);
1345 localised_family = NULL;
1349 family = NULL;
1350 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1351 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1352 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1353 break;
1354 family = NULL;
1356 if(!family) {
1357 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1358 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1359 list_init(&family->faces);
1360 list_add_tail(&font_list, &family->entry);
1362 if(localised_family) {
1363 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1364 subst->from.name = strdupW(english_family);
1365 subst->from.charset = -1;
1366 subst->to.name = strdupW(localised_family);
1367 subst->to.charset = -1;
1368 add_font_subst(&font_subst_list, subst, 0);
1371 HeapFree(GetProcessHeap(), 0, localised_family);
1372 HeapFree(GetProcessHeap(), 0, english_family);
1374 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1375 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1376 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1378 internal_leading = 0;
1379 memset(&fs, 0, sizeof(fs));
1381 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1382 if(pOS2) {
1383 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1384 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1385 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1386 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1387 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1388 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1389 if(pOS2->version == 0) {
1390 FT_UInt dummy;
1392 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1393 fs.fsCsb[0] |= FS_LATIN1;
1394 else
1395 fs.fsCsb[0] |= FS_SYMBOL;
1398 #ifdef HAVE_FREETYPE_FTWINFNT_H
1399 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1400 CHARSETINFO csi;
1401 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1402 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1403 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1404 fs = csi.fs;
1405 internal_leading = winfnt_header.internal_leading;
1407 #endif
1409 face_elem_ptr = list_head(&family->faces);
1410 while(face_elem_ptr) {
1411 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1412 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1413 if(!strcmpW(face->StyleName, StyleW) &&
1414 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1415 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1416 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1417 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1419 if(fake_family) {
1420 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1421 HeapFree(GetProcessHeap(), 0, StyleW);
1422 pFT_Done_Face(ft_face);
1423 return 1;
1425 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1426 TRACE("Original font is newer so skipping this one\n");
1427 HeapFree(GetProcessHeap(), 0, StyleW);
1428 pFT_Done_Face(ft_face);
1429 return 1;
1430 } else {
1431 TRACE("Replacing original with this one\n");
1432 list_remove(&face->entry);
1433 HeapFree(GetProcessHeap(), 0, face->file);
1434 HeapFree(GetProcessHeap(), 0, face->StyleName);
1435 HeapFree(GetProcessHeap(), 0, face);
1436 break;
1440 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1441 face->cached_enum_data = NULL;
1442 face->StyleName = StyleW;
1443 if (file)
1445 face->file = strdupA(file);
1446 face->font_data_ptr = NULL;
1447 face->font_data_size = 0;
1449 else
1451 face->file = NULL;
1452 face->font_data_ptr = font_data_ptr;
1453 face->font_data_size = font_data_size;
1455 face->face_index = face_index;
1456 face->ntmFlags = 0;
1457 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1458 face->ntmFlags |= NTM_ITALIC;
1459 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1460 face->ntmFlags |= NTM_BOLD;
1461 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1462 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1463 face->family = family;
1464 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1465 face->fs = fs;
1466 memset(&face->fs_links, 0, sizeof(face->fs_links));
1468 if(FT_IS_SCALABLE(ft_face)) {
1469 memset(&face->size, 0, sizeof(face->size));
1470 face->scalable = TRUE;
1471 } else {
1472 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1473 size->height, size->width, size->size >> 6,
1474 size->x_ppem >> 6, size->y_ppem >> 6);
1475 face->size.height = size->height;
1476 face->size.width = size->width;
1477 face->size.size = size->size;
1478 face->size.x_ppem = size->x_ppem;
1479 face->size.y_ppem = size->y_ppem;
1480 face->size.internal_leading = internal_leading;
1481 face->scalable = FALSE;
1484 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1485 tmp_size = 0;
1486 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1488 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1489 face->ntmFlags |= NTM_PS_OPENTYPE;
1492 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1493 face->fs.fsCsb[0], face->fs.fsCsb[1],
1494 face->fs.fsUsb[0], face->fs.fsUsb[1],
1495 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1498 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1499 for(i = 0; i < ft_face->num_charmaps; i++) {
1500 switch(ft_face->charmaps[i]->encoding) {
1501 case FT_ENCODING_UNICODE:
1502 case FT_ENCODING_APPLE_ROMAN:
1503 face->fs.fsCsb[0] |= FS_LATIN1;
1504 break;
1505 case FT_ENCODING_MS_SYMBOL:
1506 face->fs.fsCsb[0] |= FS_SYMBOL;
1507 break;
1508 default:
1509 break;
1514 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1515 have_installed_roman_font = TRUE;
1517 AddFaceToFamily(face, family);
1519 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1521 num_faces = ft_face->num_faces;
1522 pFT_Done_Face(ft_face);
1523 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1524 debugstr_w(StyleW));
1525 } while(num_faces > ++face_index);
1526 return num_faces;
1529 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1531 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1534 static void DumpFontList(void)
1536 Family *family;
1537 Face *face;
1538 struct list *family_elem_ptr, *face_elem_ptr;
1540 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1541 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1542 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1543 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1544 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1545 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1546 if(!face->scalable)
1547 TRACE(" %d", face->size.height);
1548 TRACE("\n");
1551 return;
1554 /***********************************************************
1555 * The replacement list is a way to map an entire font
1556 * family onto another family. For example adding
1558 * [HKCU\Software\Wine\Fonts\Replacements]
1559 * "Wingdings"="Winedings"
1561 * would enumerate the Winedings font both as Winedings and
1562 * Wingdings. However if a real Wingdings font is present the
1563 * replacement does not take place.
1566 static void LoadReplaceList(void)
1568 HKEY hkey;
1569 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1570 LPWSTR value;
1571 LPVOID data;
1572 Family *family;
1573 Face *face;
1574 struct list *family_elem_ptr, *face_elem_ptr;
1575 CHAR familyA[400];
1577 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1578 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1580 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1581 &valuelen, &datalen, NULL, NULL);
1583 valuelen++; /* returned value doesn't include room for '\0' */
1584 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1585 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1587 dlen = datalen;
1588 vlen = valuelen;
1589 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1590 &dlen) == ERROR_SUCCESS) {
1591 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1592 /* "NewName"="Oldname" */
1593 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1595 /* Find the old family and hence all of the font files
1596 in that family */
1597 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1598 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1599 if(!strcmpiW(family->FamilyName, data)) {
1600 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1601 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1602 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1603 debugstr_w(face->StyleName), familyA);
1604 /* Now add a new entry with the new family name */
1605 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1607 break;
1610 /* reset dlen and vlen */
1611 dlen = datalen;
1612 vlen = valuelen;
1614 HeapFree(GetProcessHeap(), 0, data);
1615 HeapFree(GetProcessHeap(), 0, value);
1616 RegCloseKey(hkey);
1620 /*************************************************************
1621 * init_system_links
1623 static BOOL init_system_links(void)
1625 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1626 'W','i','n','d','o','w','s',' ','N','T','\\',
1627 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1628 'S','y','s','t','e','m','L','i','n','k',0};
1629 HKEY hkey;
1630 BOOL ret = FALSE;
1631 DWORD type, max_val, max_data, val_len, data_len, index;
1632 WCHAR *value, *data;
1633 WCHAR *entry, *next;
1634 SYSTEM_LINKS *font_link, *system_font_link;
1635 CHILD_FONT *child_font;
1636 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1637 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1638 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1639 FONTSIGNATURE fs;
1640 Family *family;
1641 Face *face;
1642 FontSubst *psub;
1644 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1646 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1647 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1648 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1649 val_len = max_val + 1;
1650 data_len = max_data;
1651 index = 0;
1652 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1654 TRACE("%s:\n", debugstr_w(value));
1656 memset(&fs, 0, sizeof(fs));
1657 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1658 psub = get_font_subst(&font_subst_list, value, -1);
1659 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1660 list_init(&font_link->links);
1661 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1663 WCHAR *face_name;
1664 CHILD_FONT *child_font;
1666 TRACE("\t%s\n", debugstr_w(entry));
1668 next = entry + strlenW(entry) + 1;
1670 face_name = strchrW(entry, ',');
1671 if(face_name)
1673 *face_name++ = 0;
1674 while(isspaceW(*face_name))
1675 face_name++;
1677 psub = get_font_subst(&font_subst_list, face_name, -1);
1678 if(psub)
1679 face_name = psub->to.name;
1681 face = find_face_from_filename(entry, face_name);
1682 if(!face)
1684 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1685 continue;
1688 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1689 child_font->face = face;
1690 child_font->font = NULL;
1691 fs.fsCsb[0] |= face->fs.fsCsb[0];
1692 fs.fsCsb[1] |= face->fs.fsCsb[1];
1693 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1694 list_add_tail(&font_link->links, &child_font->entry);
1696 family = find_family_from_name(font_link->font_name);
1697 if(family)
1699 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1701 face->fs_links = fs;
1704 list_add_tail(&system_links, &font_link->entry);
1705 val_len = max_val + 1;
1706 data_len = max_data;
1709 HeapFree(GetProcessHeap(), 0, value);
1710 HeapFree(GetProcessHeap(), 0, data);
1711 RegCloseKey(hkey);
1714 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1715 that Tahoma has */
1717 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1718 system_font_link->font_name = strdupW(System);
1719 list_init(&system_font_link->links);
1721 face = find_face_from_filename(tahoma_ttf, Tahoma);
1722 if(face)
1724 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1725 child_font->face = face;
1726 child_font->font = NULL;
1727 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1728 list_add_tail(&system_font_link->links, &child_font->entry);
1730 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1732 if(!strcmpiW(font_link->font_name, Tahoma))
1734 CHILD_FONT *font_link_entry;
1735 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1737 CHILD_FONT *new_child;
1738 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1739 new_child->face = font_link_entry->face;
1740 new_child->font = NULL;
1741 list_add_tail(&system_font_link->links, &new_child->entry);
1743 break;
1746 list_add_tail(&system_links, &system_font_link->entry);
1747 return ret;
1750 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1752 DIR *dir;
1753 struct dirent *dent;
1754 char path[MAX_PATH];
1756 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1758 dir = opendir(dirname);
1759 if(!dir) {
1760 WARN("Can't open directory %s\n", debugstr_a(dirname));
1761 return FALSE;
1763 while((dent = readdir(dir)) != NULL) {
1764 struct stat statbuf;
1766 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1767 continue;
1769 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1771 sprintf(path, "%s/%s", dirname, dent->d_name);
1773 if(stat(path, &statbuf) == -1)
1775 WARN("Can't stat %s\n", debugstr_a(path));
1776 continue;
1778 if(S_ISDIR(statbuf.st_mode))
1779 ReadFontDir(path, external_fonts);
1780 else
1781 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1783 closedir(dir);
1784 return TRUE;
1787 static void load_fontconfig_fonts(void)
1789 #ifdef SONAME_LIBFONTCONFIG
1790 void *fc_handle = NULL;
1791 FcConfig *config;
1792 FcPattern *pat;
1793 FcObjectSet *os;
1794 FcFontSet *fontset;
1795 int i, len;
1796 char *file;
1797 const char *ext;
1799 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1800 if(!fc_handle) {
1801 TRACE("Wine cannot find the fontconfig library (%s).\n",
1802 SONAME_LIBFONTCONFIG);
1803 return;
1805 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1806 LOAD_FUNCPTR(FcConfigGetCurrent);
1807 LOAD_FUNCPTR(FcFontList);
1808 LOAD_FUNCPTR(FcFontSetDestroy);
1809 LOAD_FUNCPTR(FcInit);
1810 LOAD_FUNCPTR(FcObjectSetAdd);
1811 LOAD_FUNCPTR(FcObjectSetCreate);
1812 LOAD_FUNCPTR(FcObjectSetDestroy);
1813 LOAD_FUNCPTR(FcPatternCreate);
1814 LOAD_FUNCPTR(FcPatternDestroy);
1815 LOAD_FUNCPTR(FcPatternGetBool);
1816 LOAD_FUNCPTR(FcPatternGetString);
1817 #undef LOAD_FUNCPTR
1819 if(!pFcInit()) return;
1821 config = pFcConfigGetCurrent();
1822 pat = pFcPatternCreate();
1823 os = pFcObjectSetCreate();
1824 pFcObjectSetAdd(os, FC_FILE);
1825 pFcObjectSetAdd(os, FC_SCALABLE);
1826 fontset = pFcFontList(config, pat, os);
1827 if(!fontset) return;
1828 for(i = 0; i < fontset->nfont; i++) {
1829 FcBool scalable;
1831 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1832 continue;
1833 TRACE("fontconfig: %s\n", file);
1835 /* We're just interested in OT/TT fonts for now, so this hack just
1836 picks up the scalable fonts without extensions .pf[ab] to save time
1837 loading every other font */
1839 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1841 TRACE("not scalable\n");
1842 continue;
1845 len = strlen( file );
1846 if(len < 4) continue;
1847 ext = &file[ len - 3 ];
1848 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1849 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1851 pFcFontSetDestroy(fontset);
1852 pFcObjectSetDestroy(os);
1853 pFcPatternDestroy(pat);
1854 sym_not_found:
1855 #endif
1856 return;
1859 static BOOL load_font_from_data_dir(LPCWSTR file)
1861 BOOL ret = FALSE;
1862 const char *data_dir = wine_get_data_dir();
1864 if (!data_dir) data_dir = wine_get_build_dir();
1866 if (data_dir)
1868 INT len;
1869 char *unix_name;
1871 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1873 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1875 strcpy(unix_name, data_dir);
1876 strcat(unix_name, "/fonts/");
1878 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1880 EnterCriticalSection( &freetype_cs );
1881 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1882 LeaveCriticalSection( &freetype_cs );
1883 HeapFree(GetProcessHeap(), 0, unix_name);
1885 return ret;
1888 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1890 static const WCHAR slashW[] = {'\\','\0'};
1891 BOOL ret = FALSE;
1892 WCHAR windowsdir[MAX_PATH];
1893 char *unixname;
1895 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1896 strcatW(windowsdir, fontsW);
1897 strcatW(windowsdir, slashW);
1898 strcatW(windowsdir, file);
1899 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1900 EnterCriticalSection( &freetype_cs );
1901 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1902 LeaveCriticalSection( &freetype_cs );
1903 HeapFree(GetProcessHeap(), 0, unixname);
1905 return ret;
1908 static void load_system_fonts(void)
1910 HKEY hkey;
1911 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1912 const WCHAR * const *value;
1913 DWORD dlen, type;
1914 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1915 char *unixname;
1917 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1918 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1919 strcatW(windowsdir, fontsW);
1920 for(value = SystemFontValues; *value; value++) {
1921 dlen = sizeof(data);
1922 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1923 type == REG_SZ) {
1924 BOOL added = FALSE;
1926 sprintfW(pathW, fmtW, windowsdir, data);
1927 if((unixname = wine_get_unix_file_name(pathW))) {
1928 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1929 HeapFree(GetProcessHeap(), 0, unixname);
1931 if (!added)
1932 load_font_from_data_dir(data);
1935 RegCloseKey(hkey);
1939 /*************************************************************
1941 * This adds registry entries for any externally loaded fonts
1942 * (fonts from fontconfig or FontDirs). It also deletes entries
1943 * of no longer existing fonts.
1946 static void update_reg_entries(void)
1948 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1949 LPWSTR valueW;
1950 DWORD len, len_fam;
1951 Family *family;
1952 Face *face;
1953 struct list *family_elem_ptr, *face_elem_ptr;
1954 WCHAR *file;
1955 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1956 static const WCHAR spaceW[] = {' ', '\0'};
1957 char *path;
1959 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1960 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1961 ERR("Can't create Windows font reg key\n");
1962 goto end;
1965 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1966 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1967 ERR("Can't create Windows font reg key\n");
1968 goto end;
1971 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1972 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1973 ERR("Can't create external font reg key\n");
1974 goto end;
1977 /* enumerate the fonts and add external ones to the two keys */
1979 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1980 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1981 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1982 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1983 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1984 if(!face->external) continue;
1985 len = len_fam;
1986 if (!(face->ntmFlags & NTM_REGULAR))
1987 len = len_fam + strlenW(face->StyleName) + 1;
1988 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1989 strcpyW(valueW, family->FamilyName);
1990 if(len != len_fam) {
1991 strcatW(valueW, spaceW);
1992 strcatW(valueW, face->StyleName);
1994 strcatW(valueW, TrueType);
1996 file = wine_get_dos_file_name(face->file);
1997 if(file)
1998 len = strlenW(file) + 1;
1999 else
2001 if((path = strrchr(face->file, '/')) == NULL)
2002 path = face->file;
2003 else
2004 path++;
2005 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2007 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2008 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2010 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2011 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2012 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2014 HeapFree(GetProcessHeap(), 0, file);
2015 HeapFree(GetProcessHeap(), 0, valueW);
2018 end:
2019 if(external_key) RegCloseKey(external_key);
2020 if(win9x_key) RegCloseKey(win9x_key);
2021 if(winnt_key) RegCloseKey(winnt_key);
2022 return;
2025 static void delete_external_font_keys(void)
2027 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2028 DWORD dlen, vlen, datalen, valuelen, i, type;
2029 LPWSTR valueW;
2030 LPVOID data;
2032 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2033 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2034 ERR("Can't create Windows font reg key\n");
2035 goto end;
2038 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2039 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2040 ERR("Can't create Windows font reg key\n");
2041 goto end;
2044 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2045 ERR("Can't create external font reg key\n");
2046 goto end;
2049 /* Delete all external fonts added last time */
2051 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2052 &valuelen, &datalen, NULL, NULL);
2053 valuelen++; /* returned value doesn't include room for '\0' */
2054 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2055 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2057 dlen = datalen * sizeof(WCHAR);
2058 vlen = valuelen;
2059 i = 0;
2060 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2061 &dlen) == ERROR_SUCCESS) {
2063 RegDeleteValueW(winnt_key, valueW);
2064 RegDeleteValueW(win9x_key, valueW);
2065 /* reset dlen and vlen */
2066 dlen = datalen;
2067 vlen = valuelen;
2069 HeapFree(GetProcessHeap(), 0, data);
2070 HeapFree(GetProcessHeap(), 0, valueW);
2072 /* Delete the old external fonts key */
2073 RegCloseKey(external_key);
2074 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2076 end:
2077 if(win9x_key) RegCloseKey(win9x_key);
2078 if(winnt_key) RegCloseKey(winnt_key);
2081 /*************************************************************
2082 * WineEngAddFontResourceEx
2085 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2087 INT ret = 0;
2088 if (ft_handle) /* do it only if we have freetype up and running */
2090 char *unixname;
2092 if(flags)
2093 FIXME("Ignoring flags %x\n", flags);
2095 if((unixname = wine_get_unix_file_name(file)))
2097 EnterCriticalSection( &freetype_cs );
2098 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2099 LeaveCriticalSection( &freetype_cs );
2100 HeapFree(GetProcessHeap(), 0, unixname);
2102 if (!ret && !strchrW(file, '\\')) {
2103 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2104 ret = load_font_from_winfonts_dir(file);
2105 if (!ret) {
2106 /* Try in datadir/fonts (or builddir/fonts),
2107 * needed for Magic the Gathering Online
2109 ret = load_font_from_data_dir(file);
2113 return ret;
2116 /*************************************************************
2117 * WineEngAddFontMemResourceEx
2120 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2122 if (ft_handle) /* do it only if we have freetype up and running */
2124 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2126 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2127 memcpy(pFontCopy, pbFont, cbFont);
2129 EnterCriticalSection( &freetype_cs );
2130 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2131 LeaveCriticalSection( &freetype_cs );
2133 if (*pcFonts == 0)
2135 TRACE("AddFontToList failed\n");
2136 HeapFree(GetProcessHeap(), 0, pFontCopy);
2137 return NULL;
2139 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2140 * For now return something unique but quite random
2142 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2143 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2146 *pcFonts = 0;
2147 return 0;
2150 /*************************************************************
2151 * WineEngRemoveFontResourceEx
2154 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2156 FIXME(":stub\n");
2157 return TRUE;
2160 static const struct nls_update_font_list
2162 UINT ansi_cp, oem_cp;
2163 const char *oem, *fixed, *system;
2164 const char *courier, *serif, *small, *sserif;
2165 /* these are for font substitutes */
2166 const char *shelldlg, *tmsrmn;
2167 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2168 *helv_0, *tmsrmn_0;
2169 const struct subst
2171 const char *from, *to;
2172 } arial_0, courier_new_0, times_new_roman_0;
2173 } nls_update_font_list[] =
2175 /* Latin 1 (United States) */
2176 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2177 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2178 "Tahoma","Times New Roman",
2179 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2180 { 0 }, { 0 }, { 0 }
2182 /* Latin 1 (Multilingual) */
2183 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2184 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2185 "Tahoma","Times New Roman", /* FIXME unverified */
2186 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2187 { 0 }, { 0 }, { 0 }
2189 /* Eastern Europe */
2190 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2191 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2192 "Tahoma","Times New Roman", /* FIXME unverified */
2193 "Fixedsys,238", "System,238",
2194 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2195 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2196 { "Arial CE,0", "Arial,238" },
2197 { "Courier New CE,0", "Courier New,238" },
2198 { "Times New Roman CE,0", "Times New Roman,238" }
2200 /* Cyrillic */
2201 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2202 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2203 "Tahoma","Times New Roman", /* FIXME unverified */
2204 "Fixedsys,204", "System,204",
2205 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2206 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2207 { "Arial Cyr,0", "Arial,204" },
2208 { "Courier New Cyr,0", "Courier New,204" },
2209 { "Times New Roman Cyr,0", "Times New Roman,204" }
2211 /* Greek */
2212 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2213 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2214 "Tahoma","Times New Roman", /* FIXME unverified */
2215 "Fixedsys,161", "System,161",
2216 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2217 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2218 { "Arial Greek,0", "Arial,161" },
2219 { "Courier New Greek,0", "Courier New,161" },
2220 { "Times New Roman Greek,0", "Times New Roman,161" }
2222 /* Turkish */
2223 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2224 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2225 "Tahoma","Times New Roman", /* FIXME unverified */
2226 "Fixedsys,162", "System,162",
2227 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2228 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2229 { "Arial Tur,0", "Arial,162" },
2230 { "Courier New Tur,0", "Courier New,162" },
2231 { "Times New Roman Tur,0", "Times New Roman,162" }
2233 /* Hebrew */
2234 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2235 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2236 "Tahoma","Times New Roman", /* FIXME unverified */
2237 "Fixedsys,177", "System,177",
2238 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2239 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2240 { 0 }, { 0 }, { 0 }
2242 /* Arabic */
2243 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2244 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,178", "System,178",
2247 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2248 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2249 { 0 }, { 0 }, { 0 }
2251 /* Baltic */
2252 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2253 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2254 "Tahoma","Times New Roman", /* FIXME unverified */
2255 "Fixedsys,186", "System,186",
2256 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2257 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2258 { "Arial Baltic,0", "Arial,186" },
2259 { "Courier New Baltic,0", "Courier New,186" },
2260 { "Times New Roman Baltic,0", "Times New Roman,186" }
2262 /* Vietnamese */
2263 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2264 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2265 "Tahoma","Times New Roman", /* FIXME unverified */
2266 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2267 { 0 }, { 0 }, { 0 }
2269 /* Thai */
2270 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2271 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2272 "Tahoma","Times New Roman", /* FIXME unverified */
2273 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2274 { 0 }, { 0 }, { 0 }
2276 /* Japanese */
2277 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2278 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2279 "MS UI Gothic","MS Serif",
2280 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2281 { 0 }, { 0 }, { 0 }
2283 /* Chinese Simplified */
2284 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2285 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2286 "SimSun", "NSimSun",
2287 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2288 { 0 }, { 0 }, { 0 }
2290 /* Korean */
2291 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2292 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2293 "Gulim", "Batang",
2294 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2295 { 0 }, { 0 }, { 0 }
2297 /* Chinese Traditional */
2298 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2299 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2300 "PMingLiU", "MingLiU",
2301 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2302 { 0 }, { 0 }, { 0 }
2306 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2308 return ( ansi_cp == 932 /* CP932 for Japanese */
2309 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2310 || ansi_cp == 949 /* CP949 for Korean */
2311 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2314 static inline HKEY create_fonts_NT_registry_key(void)
2316 HKEY hkey = 0;
2318 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2319 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2320 return hkey;
2323 static inline HKEY create_fonts_9x_registry_key(void)
2325 HKEY hkey = 0;
2327 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2328 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2329 return hkey;
2332 static inline HKEY create_config_fonts_registry_key(void)
2334 HKEY hkey = 0;
2336 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2337 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2338 return hkey;
2341 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2343 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2344 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2345 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2346 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2349 static void set_value_key(HKEY hkey, const char *name, const char *value)
2351 if (value)
2352 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2353 else if (name)
2354 RegDeleteValueA(hkey, name);
2357 static void update_font_info(void)
2359 char buf[40], cpbuf[40];
2360 DWORD len, type;
2361 HKEY hkey = 0;
2362 UINT i, ansi_cp = 0, oem_cp = 0;
2363 BOOL done = FALSE;
2365 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2366 return;
2368 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2369 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2370 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2371 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2372 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2374 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2375 if (is_dbcs_ansi_cp(ansi_cp))
2376 use_default_fallback = TRUE;
2378 len = sizeof(buf);
2379 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2381 if (!strcmp( buf, cpbuf )) /* already set correctly */
2383 RegCloseKey(hkey);
2384 return;
2386 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2388 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2390 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2391 RegCloseKey(hkey);
2393 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2395 HKEY hkey;
2397 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2398 nls_update_font_list[i].oem_cp == oem_cp)
2400 hkey = create_config_fonts_registry_key();
2401 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2402 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2403 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2404 RegCloseKey(hkey);
2406 hkey = create_fonts_NT_registry_key();
2407 add_font_list(hkey, &nls_update_font_list[i]);
2408 RegCloseKey(hkey);
2410 hkey = create_fonts_9x_registry_key();
2411 add_font_list(hkey, &nls_update_font_list[i]);
2412 RegCloseKey(hkey);
2414 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2416 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2417 strlen(nls_update_font_list[i].shelldlg)+1);
2418 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2419 strlen(nls_update_font_list[i].tmsrmn)+1);
2421 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2422 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2423 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2424 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2425 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2426 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2427 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2428 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2430 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2431 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2432 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2434 RegCloseKey(hkey);
2436 done = TRUE;
2438 else
2440 /* Delete the FontSubstitutes from other locales */
2441 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2443 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2444 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2445 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2446 RegCloseKey(hkey);
2450 if (!done)
2451 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2455 static BOOL init_freetype(void)
2457 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2458 if(!ft_handle) {
2459 WINE_MESSAGE(
2460 "Wine cannot find the FreeType font library. To enable Wine to\n"
2461 "use TrueType fonts please install a version of FreeType greater than\n"
2462 "or equal to 2.0.5.\n"
2463 "http://www.freetype.org\n");
2464 return FALSE;
2467 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2469 LOAD_FUNCPTR(FT_Vector_Unit)
2470 LOAD_FUNCPTR(FT_Done_Face)
2471 LOAD_FUNCPTR(FT_Get_Char_Index)
2472 LOAD_FUNCPTR(FT_Get_Module)
2473 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2474 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2475 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2476 LOAD_FUNCPTR(FT_Init_FreeType)
2477 LOAD_FUNCPTR(FT_Load_Glyph)
2478 LOAD_FUNCPTR(FT_Matrix_Multiply)
2479 #ifndef FT_MULFIX_INLINED
2480 LOAD_FUNCPTR(FT_MulFix)
2481 #endif
2482 LOAD_FUNCPTR(FT_New_Face)
2483 LOAD_FUNCPTR(FT_New_Memory_Face)
2484 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2485 LOAD_FUNCPTR(FT_Outline_Transform)
2486 LOAD_FUNCPTR(FT_Outline_Translate)
2487 LOAD_FUNCPTR(FT_Select_Charmap)
2488 LOAD_FUNCPTR(FT_Set_Charmap)
2489 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2490 LOAD_FUNCPTR(FT_Vector_Transform)
2491 LOAD_FUNCPTR(FT_Render_Glyph)
2493 #undef LOAD_FUNCPTR
2494 /* Don't warn if these ones are missing */
2495 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2496 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2497 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2498 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2499 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2500 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2501 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2502 #endif
2503 #ifdef HAVE_FREETYPE_FTWINFNT_H
2504 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2505 #endif
2506 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2507 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2508 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2509 <= 2.0.3 has FT_Sqrt64 */
2510 goto sym_not_found;
2513 if(pFT_Init_FreeType(&library) != 0) {
2514 ERR("Can't init FreeType library\n");
2515 wine_dlclose(ft_handle, NULL, 0);
2516 ft_handle = NULL;
2517 return FALSE;
2519 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2520 if (pFT_Library_Version)
2521 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2523 if (FT_Version.major<=0)
2525 FT_Version.major=2;
2526 FT_Version.minor=0;
2527 FT_Version.patch=5;
2529 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2530 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2531 ((FT_Version.minor << 8) & 0x00ff00) |
2532 ((FT_Version.patch ) & 0x0000ff);
2534 return TRUE;
2536 sym_not_found:
2537 WINE_MESSAGE(
2538 "Wine cannot find certain functions that it needs inside the FreeType\n"
2539 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2540 "FreeType to at least version 2.0.5.\n"
2541 "http://www.freetype.org\n");
2542 wine_dlclose(ft_handle, NULL, 0);
2543 ft_handle = NULL;
2544 return FALSE;
2547 /*************************************************************
2548 * WineEngInit
2550 * Initialize FreeType library and create a list of available faces
2552 BOOL WineEngInit(void)
2554 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2555 static const WCHAR pathW[] = {'P','a','t','h',0};
2556 HKEY hkey;
2557 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2558 LPVOID data;
2559 WCHAR windowsdir[MAX_PATH];
2560 char *unixname;
2561 HANDLE font_mutex;
2562 const char *data_dir;
2564 TRACE("\n");
2566 /* update locale dependent font info in registry */
2567 update_font_info();
2569 if(!init_freetype()) return FALSE;
2571 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2572 ERR("Failed to create font mutex\n");
2573 return FALSE;
2575 WaitForSingleObject(font_mutex, INFINITE);
2577 delete_external_font_keys();
2579 /* load the system bitmap fonts */
2580 load_system_fonts();
2582 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2583 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2584 strcatW(windowsdir, fontsW);
2585 if((unixname = wine_get_unix_file_name(windowsdir)))
2587 ReadFontDir(unixname, FALSE);
2588 HeapFree(GetProcessHeap(), 0, unixname);
2591 /* load the system truetype fonts */
2592 data_dir = wine_get_data_dir();
2593 if (!data_dir) data_dir = wine_get_build_dir();
2594 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2595 strcpy(unixname, data_dir);
2596 strcat(unixname, "/fonts/");
2597 ReadFontDir(unixname, TRUE);
2598 HeapFree(GetProcessHeap(), 0, unixname);
2601 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2602 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2603 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2604 will skip these. */
2605 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2606 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2607 &hkey) == ERROR_SUCCESS) {
2608 LPWSTR valueW;
2609 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2610 &valuelen, &datalen, NULL, NULL);
2612 valuelen++; /* returned value doesn't include room for '\0' */
2613 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2614 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2615 if (valueW && data)
2617 dlen = datalen * sizeof(WCHAR);
2618 vlen = valuelen;
2619 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2620 &dlen) == ERROR_SUCCESS) {
2621 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2623 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2625 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2626 HeapFree(GetProcessHeap(), 0, unixname);
2629 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2631 WCHAR pathW[MAX_PATH];
2632 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2633 BOOL added = FALSE;
2635 sprintfW(pathW, fmtW, windowsdir, data);
2636 if((unixname = wine_get_unix_file_name(pathW)))
2638 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2639 HeapFree(GetProcessHeap(), 0, unixname);
2641 if (!added)
2642 load_font_from_data_dir(data);
2644 /* reset dlen and vlen */
2645 dlen = datalen;
2646 vlen = valuelen;
2649 HeapFree(GetProcessHeap(), 0, data);
2650 HeapFree(GetProcessHeap(), 0, valueW);
2651 RegCloseKey(hkey);
2654 load_fontconfig_fonts();
2656 /* then look in any directories that we've specified in the config file */
2657 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2658 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2660 DWORD len;
2661 LPWSTR valueW;
2662 LPSTR valueA, ptr;
2664 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2666 len += sizeof(WCHAR);
2667 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2668 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2670 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2671 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2672 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2673 TRACE( "got font path %s\n", debugstr_a(valueA) );
2674 ptr = valueA;
2675 while (ptr)
2677 LPSTR next = strchr( ptr, ':' );
2678 if (next) *next++ = 0;
2679 ReadFontDir( ptr, TRUE );
2680 ptr = next;
2682 HeapFree( GetProcessHeap(), 0, valueA );
2684 HeapFree( GetProcessHeap(), 0, valueW );
2686 RegCloseKey(hkey);
2689 DumpFontList();
2690 LoadSubstList();
2691 DumpSubstList();
2692 LoadReplaceList();
2693 update_reg_entries();
2695 init_system_links();
2697 ReleaseMutex(font_mutex);
2698 return TRUE;
2702 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2704 TT_OS2 *pOS2;
2705 TT_HoriHeader *pHori;
2707 LONG ppem;
2709 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2710 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2712 if(height == 0) height = 16;
2714 /* Calc. height of EM square:
2716 * For +ve lfHeight we have
2717 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2718 * Re-arranging gives:
2719 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2721 * For -ve lfHeight we have
2722 * |lfHeight| = ppem
2723 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2724 * with il = winAscent + winDescent - units_per_em]
2728 if(height > 0) {
2729 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2730 ppem = MulDiv(ft_face->units_per_EM, height,
2731 pHori->Ascender - pHori->Descender);
2732 else
2733 ppem = MulDiv(ft_face->units_per_EM, height,
2734 pOS2->usWinAscent + pOS2->usWinDescent);
2736 else
2737 ppem = -height;
2739 return ppem;
2742 static struct font_mapping *map_font_file( const char *name )
2744 struct font_mapping *mapping;
2745 struct stat st;
2746 int fd;
2748 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2749 if (fstat( fd, &st ) == -1) goto error;
2751 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2753 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2755 mapping->refcount++;
2756 close( fd );
2757 return mapping;
2760 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2761 goto error;
2763 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2764 close( fd );
2766 if (mapping->data == MAP_FAILED)
2768 HeapFree( GetProcessHeap(), 0, mapping );
2769 return NULL;
2771 mapping->refcount = 1;
2772 mapping->dev = st.st_dev;
2773 mapping->ino = st.st_ino;
2774 mapping->size = st.st_size;
2775 list_add_tail( &mappings_list, &mapping->entry );
2776 return mapping;
2778 error:
2779 close( fd );
2780 return NULL;
2783 static void unmap_font_file( struct font_mapping *mapping )
2785 if (!--mapping->refcount)
2787 list_remove( &mapping->entry );
2788 munmap( mapping->data, mapping->size );
2789 HeapFree( GetProcessHeap(), 0, mapping );
2793 static LONG load_VDMX(GdiFont*, LONG);
2795 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2797 FT_Error err;
2798 FT_Face ft_face;
2799 void *data_ptr;
2800 DWORD data_size;
2802 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2804 if (face->file)
2806 if (!(font->mapping = map_font_file( face->file )))
2808 WARN("failed to map %s\n", debugstr_a(face->file));
2809 return 0;
2811 data_ptr = font->mapping->data;
2812 data_size = font->mapping->size;
2814 else
2816 data_ptr = face->font_data_ptr;
2817 data_size = face->font_data_size;
2820 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2821 if(err) {
2822 ERR("FT_New_Face rets %d\n", err);
2823 return 0;
2826 /* set it here, as load_VDMX needs it */
2827 font->ft_face = ft_face;
2829 if(FT_IS_SCALABLE(ft_face)) {
2830 /* load the VDMX table if we have one */
2831 font->ppem = load_VDMX(font, height);
2832 if(font->ppem == 0)
2833 font->ppem = calc_ppem_for_height(ft_face, height);
2834 TRACE("height %d => ppem %d\n", height, font->ppem);
2836 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2837 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2838 } else {
2839 font->ppem = height;
2840 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2841 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2843 return ft_face;
2847 static int get_nearest_charset(Face *face, int *cp)
2849 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2850 a single face with the requested charset. The idea is to check if
2851 the selected font supports the current ANSI codepage, if it does
2852 return the corresponding charset, else return the first charset */
2854 CHARSETINFO csi;
2855 int acp = GetACP(), i;
2856 DWORD fs0;
2858 *cp = acp;
2859 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2860 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2861 return csi.ciCharset;
2863 for(i = 0; i < 32; i++) {
2864 fs0 = 1L << i;
2865 if(face->fs.fsCsb[0] & fs0) {
2866 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2867 *cp = csi.ciACP;
2868 return csi.ciCharset;
2870 else
2871 FIXME("TCI failing on %x\n", fs0);
2875 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2876 face->fs.fsCsb[0], face->file);
2877 *cp = acp;
2878 return DEFAULT_CHARSET;
2881 static GdiFont *alloc_font(void)
2883 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2884 ret->gmsize = 1;
2885 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2886 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2887 ret->potm = NULL;
2888 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2889 ret->total_kern_pairs = (DWORD)-1;
2890 ret->kern_pairs = NULL;
2891 list_init(&ret->hfontlist);
2892 list_init(&ret->child_fonts);
2893 return ret;
2896 static void free_font(GdiFont *font)
2898 struct list *cursor, *cursor2;
2899 DWORD i;
2901 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2903 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2904 struct list *first_hfont;
2905 HFONTLIST *hfontlist;
2906 list_remove(cursor);
2907 if(child->font)
2909 first_hfont = list_head(&child->font->hfontlist);
2910 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2911 DeleteObject(hfontlist->hfont);
2912 HeapFree(GetProcessHeap(), 0, hfontlist);
2913 free_font(child->font);
2915 HeapFree(GetProcessHeap(), 0, child);
2918 if (font->ft_face) pFT_Done_Face(font->ft_face);
2919 if (font->mapping) unmap_font_file( font->mapping );
2920 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2921 HeapFree(GetProcessHeap(), 0, font->potm);
2922 HeapFree(GetProcessHeap(), 0, font->name);
2923 for (i = 0; i < font->gmsize; i++)
2924 HeapFree(GetProcessHeap(),0,font->gm[i]);
2925 HeapFree(GetProcessHeap(), 0, font->gm);
2926 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2927 HeapFree(GetProcessHeap(), 0, font);
2931 /*************************************************************
2932 * load_VDMX
2934 * load the vdmx entry for the specified height
2937 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2938 ( ( (FT_ULong)_x4 << 24 ) | \
2939 ( (FT_ULong)_x3 << 16 ) | \
2940 ( (FT_ULong)_x2 << 8 ) | \
2941 (FT_ULong)_x1 )
2943 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2945 typedef struct {
2946 BYTE bCharSet;
2947 BYTE xRatio;
2948 BYTE yStartRatio;
2949 BYTE yEndRatio;
2950 } Ratios;
2952 typedef struct {
2953 WORD recs;
2954 BYTE startsz;
2955 BYTE endsz;
2956 } VDMX_group;
2958 static LONG load_VDMX(GdiFont *font, LONG height)
2960 WORD hdr[3], tmp;
2961 VDMX_group group;
2962 BYTE devXRatio, devYRatio;
2963 USHORT numRecs, numRatios;
2964 DWORD result, offset = -1;
2965 LONG ppem = 0;
2966 int i;
2968 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2970 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2971 return ppem;
2973 /* FIXME: need the real device aspect ratio */
2974 devXRatio = 1;
2975 devYRatio = 1;
2977 numRecs = GET_BE_WORD(hdr[1]);
2978 numRatios = GET_BE_WORD(hdr[2]);
2980 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2981 for(i = 0; i < numRatios; i++) {
2982 Ratios ratio;
2984 offset = (3 * 2) + (i * sizeof(Ratios));
2985 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2986 offset = -1;
2988 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2990 if((ratio.xRatio == 0 &&
2991 ratio.yStartRatio == 0 &&
2992 ratio.yEndRatio == 0) ||
2993 (devXRatio == ratio.xRatio &&
2994 devYRatio >= ratio.yStartRatio &&
2995 devYRatio <= ratio.yEndRatio))
2997 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2998 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2999 offset = GET_BE_WORD(tmp);
3000 break;
3004 if(offset == -1) {
3005 FIXME("No suitable ratio found\n");
3006 return ppem;
3009 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3010 USHORT recs;
3011 BYTE startsz, endsz;
3012 WORD *vTable;
3014 recs = GET_BE_WORD(group.recs);
3015 startsz = group.startsz;
3016 endsz = group.endsz;
3018 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3020 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3021 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3022 if(result == GDI_ERROR) {
3023 FIXME("Failed to retrieve vTable\n");
3024 goto end;
3027 if(height > 0) {
3028 for(i = 0; i < recs; i++) {
3029 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3030 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3031 ppem = GET_BE_WORD(vTable[i * 3]);
3033 if(yMax + -yMin == height) {
3034 font->yMax = yMax;
3035 font->yMin = yMin;
3036 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3037 break;
3039 if(yMax + -yMin > height) {
3040 if(--i < 0) {
3041 ppem = 0;
3042 goto end; /* failed */
3044 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3045 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3046 ppem = GET_BE_WORD(vTable[i * 3]);
3047 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3048 break;
3051 if(!font->yMax) {
3052 ppem = 0;
3053 TRACE("ppem not found for height %d\n", height);
3055 } else {
3056 ppem = -height;
3057 if(ppem < startsz || ppem > endsz)
3058 goto end;
3060 for(i = 0; i < recs; i++) {
3061 USHORT yPelHeight;
3062 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3064 if(yPelHeight > ppem)
3065 break; /* failed */
3067 if(yPelHeight == ppem) {
3068 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3069 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3070 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3071 break;
3075 end:
3076 HeapFree(GetProcessHeap(), 0, vTable);
3079 return ppem;
3082 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3084 if(font->font_desc.hash != fd->hash) return TRUE;
3085 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3086 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3087 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3088 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3091 static void calc_hash(FONT_DESC *pfd)
3093 DWORD hash = 0, *ptr, two_chars;
3094 WORD *pwc;
3095 unsigned int i;
3097 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3098 hash ^= *ptr;
3099 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3100 hash ^= *ptr;
3101 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3102 two_chars = *ptr;
3103 pwc = (WCHAR *)&two_chars;
3104 if(!*pwc) break;
3105 *pwc = toupperW(*pwc);
3106 pwc++;
3107 *pwc = toupperW(*pwc);
3108 hash ^= two_chars;
3109 if(!*pwc) break;
3111 hash ^= !pfd->can_use_bitmap;
3112 pfd->hash = hash;
3113 return;
3116 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3118 GdiFont *ret;
3119 FONT_DESC fd;
3120 HFONTLIST *hflist;
3121 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3123 fd.lf = *plf;
3124 fd.matrix = *pmat;
3125 fd.can_use_bitmap = can_use_bitmap;
3126 calc_hash(&fd);
3128 /* try the child list */
3129 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3130 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3131 if(!fontcmp(ret, &fd)) {
3132 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3133 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3134 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3135 if(hflist->hfont == hfont)
3136 return ret;
3141 /* try the in-use list */
3142 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3143 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3144 if(!fontcmp(ret, &fd)) {
3145 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3146 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3147 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3148 if(hflist->hfont == hfont)
3149 return ret;
3151 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3152 hflist->hfont = hfont;
3153 list_add_head(&ret->hfontlist, &hflist->entry);
3154 return ret;
3158 /* then the unused list */
3159 font_elem_ptr = list_head(&unused_gdi_font_list);
3160 while(font_elem_ptr) {
3161 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3162 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3163 if(!fontcmp(ret, &fd)) {
3164 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3165 assert(list_empty(&ret->hfontlist));
3166 TRACE("Found %p in unused list\n", ret);
3167 list_remove(&ret->entry);
3168 list_add_head(&gdi_font_list, &ret->entry);
3169 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3170 hflist->hfont = hfont;
3171 list_add_head(&ret->hfontlist, &hflist->entry);
3172 return ret;
3175 return NULL;
3178 static void add_to_cache(GdiFont *font)
3180 static DWORD cache_num = 1;
3182 font->cache_num = cache_num++;
3183 list_add_head(&gdi_font_list, &font->entry);
3186 /*************************************************************
3187 * create_child_font_list
3189 static BOOL create_child_font_list(GdiFont *font)
3191 BOOL ret = FALSE;
3192 SYSTEM_LINKS *font_link;
3193 CHILD_FONT *font_link_entry, *new_child;
3195 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3197 if(!strcmpW(font_link->font_name, font->name))
3199 TRACE("found entry in system list\n");
3200 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3202 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3203 new_child->face = font_link_entry->face;
3204 new_child->font = NULL;
3205 list_add_tail(&font->child_fonts, &new_child->entry);
3206 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3208 ret = TRUE;
3209 break;
3213 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3214 * Sans Serif. This is how asian windows get default fallbacks for fonts
3216 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3217 font->charset != OEM_CHARSET &&
3218 strcmpW(font->name,szDefaultFallbackLink) != 0)
3219 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3221 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3223 TRACE("found entry in default fallback list\n");
3224 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3226 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3227 new_child->face = font_link_entry->face;
3228 new_child->font = NULL;
3229 list_add_tail(&font->child_fonts, &new_child->entry);
3230 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3232 ret = TRUE;
3233 break;
3237 return ret;
3240 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3242 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3244 if (pFT_Set_Charmap)
3246 FT_Int i;
3247 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3249 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3251 for (i = 0; i < ft_face->num_charmaps; i++)
3253 if (ft_face->charmaps[i]->encoding == encoding)
3255 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3256 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3258 switch (ft_face->charmaps[i]->platform_id)
3260 default:
3261 cmap_def = ft_face->charmaps[i];
3262 break;
3263 case 0: /* Apple Unicode */
3264 cmap0 = ft_face->charmaps[i];
3265 break;
3266 case 1: /* Macintosh */
3267 cmap1 = ft_face->charmaps[i];
3268 break;
3269 case 2: /* ISO */
3270 cmap2 = ft_face->charmaps[i];
3271 break;
3272 case 3: /* Microsoft */
3273 cmap3 = ft_face->charmaps[i];
3274 break;
3278 if (cmap3) /* prefer Microsoft cmap table */
3279 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3280 else if (cmap1)
3281 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3282 else if (cmap2)
3283 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3284 else if (cmap0)
3285 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3286 else if (cmap_def)
3287 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3289 return ft_err == FT_Err_Ok;
3292 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3295 /*************************************************************
3296 * WineEngCreateFontInstance
3299 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3301 GdiFont *ret;
3302 Face *face, *best, *best_bitmap;
3303 Family *family, *last_resort_family;
3304 struct list *family_elem_ptr, *face_elem_ptr;
3305 INT height, width = 0;
3306 unsigned int score = 0, new_score;
3307 signed int diff = 0, newdiff;
3308 BOOL bd, it, can_use_bitmap;
3309 LOGFONTW lf;
3310 CHARSETINFO csi;
3311 HFONTLIST *hflist;
3312 FMAT2 dcmat;
3313 FontSubst *psub = NULL;
3315 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3316 lf.lfWidth = abs(lf.lfWidth);
3318 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3320 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3321 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3322 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3323 lf.lfEscapement);
3325 if(dc->GraphicsMode == GM_ADVANCED)
3326 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3327 else
3329 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3330 font scaling abilities. */
3331 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3332 dcmat.eM21 = dcmat.eM12 = 0;
3335 /* Try to avoid not necessary glyph transformations */
3336 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3338 lf.lfHeight *= fabs(dcmat.eM11);
3339 lf.lfWidth *= fabs(dcmat.eM11);
3340 dcmat.eM11 = dcmat.eM22 = 1.0;
3343 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3344 dcmat.eM21, dcmat.eM22);
3346 EnterCriticalSection( &freetype_cs );
3348 /* check the cache first */
3349 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3350 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3351 LeaveCriticalSection( &freetype_cs );
3352 return ret;
3355 TRACE("not in cache\n");
3356 if(list_empty(&font_list)) /* No fonts installed */
3358 TRACE("No fonts installed\n");
3359 LeaveCriticalSection( &freetype_cs );
3360 return NULL;
3362 if(!have_installed_roman_font)
3364 TRACE("No roman font installed\n");
3365 LeaveCriticalSection( &freetype_cs );
3366 return NULL;
3369 ret = alloc_font();
3371 ret->font_desc.matrix = dcmat;
3372 ret->font_desc.lf = lf;
3373 ret->font_desc.can_use_bitmap = can_use_bitmap;
3374 calc_hash(&ret->font_desc);
3375 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3376 hflist->hfont = hfont;
3377 list_add_head(&ret->hfontlist, &hflist->entry);
3379 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3380 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3381 original value lfCharSet. Note this is a special case for
3382 Symbol and doesn't happen at least for "Wingdings*" */
3384 if(!strcmpiW(lf.lfFaceName, SymbolW))
3385 lf.lfCharSet = SYMBOL_CHARSET;
3387 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3388 switch(lf.lfCharSet) {
3389 case DEFAULT_CHARSET:
3390 csi.fs.fsCsb[0] = 0;
3391 break;
3392 default:
3393 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3394 csi.fs.fsCsb[0] = 0;
3395 break;
3399 family = NULL;
3400 if(lf.lfFaceName[0] != '\0') {
3401 SYSTEM_LINKS *font_link;
3402 CHILD_FONT *font_link_entry;
3403 LPWSTR FaceName = lf.lfFaceName;
3406 * Check for a leading '@' this signals that the font is being
3407 * requested in tategaki mode (vertical writing substitution) but
3408 * does not affect the fontface that is to be selected.
3410 if (lf.lfFaceName[0]=='@')
3411 FaceName = &lf.lfFaceName[1];
3413 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3415 if(psub) {
3416 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3417 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3418 if (psub->to.charset != -1)
3419 lf.lfCharSet = psub->to.charset;
3422 /* We want a match on name and charset or just name if
3423 charset was DEFAULT_CHARSET. If the latter then
3424 we fixup the returned charset later in get_nearest_charset
3425 where we'll either use the charset of the current ansi codepage
3426 or if that's unavailable the first charset that the font supports.
3428 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3429 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3430 if (!strcmpiW(family->FamilyName, FaceName) ||
3431 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3433 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3434 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3435 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3436 if(face->scalable || can_use_bitmap)
3437 goto found;
3443 * Try check the SystemLink list first for a replacement font.
3444 * We may find good replacements there.
3446 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3448 if(!strcmpiW(font_link->font_name, FaceName) ||
3449 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3451 TRACE("found entry in system list\n");
3452 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3454 face = font_link_entry->face;
3455 family = face->family;
3456 if(csi.fs.fsCsb[0] &
3457 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3459 if(face->scalable || can_use_bitmap)
3460 goto found;
3467 psub = NULL; /* substitution is no more relevant */
3469 /* If requested charset was DEFAULT_CHARSET then try using charset
3470 corresponding to the current ansi codepage */
3471 if (!csi.fs.fsCsb[0])
3473 INT acp = GetACP();
3474 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3475 FIXME("TCI failed on codepage %d\n", acp);
3476 csi.fs.fsCsb[0] = 0;
3477 } else
3478 lf.lfCharSet = csi.ciCharset;
3481 /* Face families are in the top 4 bits of lfPitchAndFamily,
3482 so mask with 0xF0 before testing */
3484 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3485 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3486 strcpyW(lf.lfFaceName, defFixed);
3487 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3488 strcpyW(lf.lfFaceName, defSerif);
3489 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3490 strcpyW(lf.lfFaceName, defSans);
3491 else
3492 strcpyW(lf.lfFaceName, defSans);
3493 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3494 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3495 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3496 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3497 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3498 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3499 if(face->scalable || can_use_bitmap)
3500 goto found;
3505 last_resort_family = NULL;
3506 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3507 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3508 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3509 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3510 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3511 if(face->scalable)
3512 goto found;
3513 if(can_use_bitmap && !last_resort_family)
3514 last_resort_family = family;
3519 if(last_resort_family) {
3520 family = last_resort_family;
3521 csi.fs.fsCsb[0] = 0;
3522 goto found;
3525 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3526 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3527 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3528 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3529 if(face->scalable) {
3530 csi.fs.fsCsb[0] = 0;
3531 WARN("just using first face for now\n");
3532 goto found;
3534 if(can_use_bitmap && !last_resort_family)
3535 last_resort_family = family;
3538 if(!last_resort_family) {
3539 FIXME("can't find a single appropriate font - bailing\n");
3540 free_font(ret);
3541 LeaveCriticalSection( &freetype_cs );
3542 return NULL;
3545 WARN("could only find a bitmap font - this will probably look awful!\n");
3546 family = last_resort_family;
3547 csi.fs.fsCsb[0] = 0;
3549 found:
3550 it = lf.lfItalic ? 1 : 0;
3551 bd = lf.lfWeight > 550 ? 1 : 0;
3553 height = lf.lfHeight;
3555 face = best = best_bitmap = NULL;
3556 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3558 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3560 BOOL italic, bold;
3562 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3563 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3564 new_score = (italic ^ it) + (bold ^ bd);
3565 if(!best || new_score <= score)
3567 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3568 italic, bold, it, bd);
3569 score = new_score;
3570 best = face;
3571 if(best->scalable && score == 0) break;
3572 if(!best->scalable)
3574 if(height > 0)
3575 newdiff = height - (signed int)(best->size.height);
3576 else
3577 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3578 if(!best_bitmap || new_score < score ||
3579 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3581 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3582 diff = newdiff;
3583 best_bitmap = best;
3584 if(score == 0 && diff == 0) break;
3590 if(best)
3591 face = best->scalable ? best : best_bitmap;
3592 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3593 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3595 ret->fs = face->fs;
3597 if(csi.fs.fsCsb[0]) {
3598 ret->charset = lf.lfCharSet;
3599 ret->codepage = csi.ciACP;
3601 else
3602 ret->charset = get_nearest_charset(face, &ret->codepage);
3604 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3605 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3607 ret->aveWidth = height ? lf.lfWidth : 0;
3609 if(!face->scalable) {
3610 /* Windows uses integer scaling factors for bitmap fonts */
3611 INT scale, scaled_height;
3613 /* FIXME: rotation of bitmap fonts is ignored */
3614 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3615 if (ret->aveWidth)
3616 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3617 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3619 if (height != 0) height = diff;
3620 height += face->size.height;
3622 scale = (height + face->size.height - 1) / face->size.height;
3623 scaled_height = scale * face->size.height;
3624 /* XP allows not more than 10% deviation */
3625 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3626 ret->scale_y = scale;
3628 width = face->size.x_ppem >> 6;
3629 height = face->size.y_ppem >> 6;
3631 else
3632 ret->scale_y = 1.0;
3633 TRACE("font scale y: %f\n", ret->scale_y);
3635 ret->ft_face = OpenFontFace(ret, face, width, height);
3637 if (!ret->ft_face)
3639 free_font( ret );
3640 LeaveCriticalSection( &freetype_cs );
3641 return 0;
3644 ret->ntmFlags = face->ntmFlags;
3646 if (ret->charset == SYMBOL_CHARSET &&
3647 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3648 /* No ops */
3650 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3651 /* No ops */
3653 else {
3654 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3657 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3658 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3659 ret->underline = lf.lfUnderline ? 0xff : 0;
3660 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3661 create_child_font_list(ret);
3663 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3665 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3666 if (length != GDI_ERROR)
3668 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3669 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3670 TRACE("Loaded GSUB table of %i bytes\n",length);
3674 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3676 add_to_cache(ret);
3677 LeaveCriticalSection( &freetype_cs );
3678 return ret;
3681 static void dump_gdi_font_list(void)
3683 GdiFont *gdiFont;
3684 struct list *elem_ptr;
3686 TRACE("---------- gdiFont Cache ----------\n");
3687 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3688 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3689 TRACE("gdiFont=%p %s %d\n",
3690 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3693 TRACE("---------- Unused gdiFont Cache ----------\n");
3694 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3695 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3696 TRACE("gdiFont=%p %s %d\n",
3697 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3701 /*************************************************************
3702 * WineEngDestroyFontInstance
3704 * free the gdiFont associated with this handle
3707 BOOL WineEngDestroyFontInstance(HFONT handle)
3709 GdiFont *gdiFont;
3710 HFONTLIST *hflist;
3711 BOOL ret = FALSE;
3712 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3713 int i = 0;
3715 EnterCriticalSection( &freetype_cs );
3717 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3719 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3720 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3721 if(hflist->hfont == handle)
3723 TRACE("removing child font %p from child list\n", gdiFont);
3724 list_remove(&gdiFont->entry);
3725 LeaveCriticalSection( &freetype_cs );
3726 return TRUE;
3730 TRACE("destroying hfont=%p\n", handle);
3731 if(TRACE_ON(font))
3732 dump_gdi_font_list();
3734 font_elem_ptr = list_head(&gdi_font_list);
3735 while(font_elem_ptr) {
3736 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3737 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3739 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3740 while(hfontlist_elem_ptr) {
3741 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3742 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3743 if(hflist->hfont == handle) {
3744 list_remove(&hflist->entry);
3745 HeapFree(GetProcessHeap(), 0, hflist);
3746 ret = TRUE;
3749 if(list_empty(&gdiFont->hfontlist)) {
3750 TRACE("Moving to Unused list\n");
3751 list_remove(&gdiFont->entry);
3752 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3757 font_elem_ptr = list_head(&unused_gdi_font_list);
3758 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3759 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3760 while(font_elem_ptr) {
3761 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3762 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3763 TRACE("freeing %p\n", gdiFont);
3764 list_remove(&gdiFont->entry);
3765 free_font(gdiFont);
3767 LeaveCriticalSection( &freetype_cs );
3768 return ret;
3771 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3772 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3774 GdiFont *font;
3775 LONG width, height;
3777 if (face->cached_enum_data)
3779 TRACE("Cached\n");
3780 *pelf = face->cached_enum_data->elf;
3781 *pntm = face->cached_enum_data->ntm;
3782 *ptype = face->cached_enum_data->type;
3783 return;
3786 font = alloc_font();
3788 if(face->scalable) {
3789 height = -2048; /* 2048 is the most common em size */
3790 width = 0;
3791 } else {
3792 height = face->size.y_ppem >> 6;
3793 width = face->size.x_ppem >> 6;
3795 font->scale_y = 1.0;
3797 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3799 free_font(font);
3800 return;
3803 font->name = strdupW(face->family->FamilyName);
3804 font->ntmFlags = face->ntmFlags;
3806 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3808 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3810 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3812 lstrcpynW(pelf->elfLogFont.lfFaceName,
3813 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3814 LF_FACESIZE);
3815 lstrcpynW(pelf->elfFullName,
3816 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3817 LF_FULLFACESIZE);
3818 lstrcpynW(pelf->elfStyle,
3819 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3820 LF_FACESIZE);
3822 else
3824 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3826 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3828 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3829 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3830 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3833 pntm->ntmTm.ntmFlags = face->ntmFlags;
3834 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3835 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3836 pntm->ntmFontSig = face->fs;
3838 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3840 pelf->elfLogFont.lfEscapement = 0;
3841 pelf->elfLogFont.lfOrientation = 0;
3842 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3843 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3844 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3845 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3846 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3847 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3848 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3849 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3850 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3851 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3852 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3854 *ptype = 0;
3855 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3856 *ptype |= TRUETYPE_FONTTYPE;
3857 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3858 *ptype |= DEVICE_FONTTYPE;
3859 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3860 *ptype |= RASTER_FONTTYPE;
3862 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3863 if (face->cached_enum_data)
3865 face->cached_enum_data->elf = *pelf;
3866 face->cached_enum_data->ntm = *pntm;
3867 face->cached_enum_data->type = *ptype;
3870 free_font(font);
3873 /*************************************************************
3874 * WineEngEnumFonts
3877 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3879 Family *family;
3880 Face *face;
3881 struct list *family_elem_ptr, *face_elem_ptr;
3882 ENUMLOGFONTEXW elf;
3883 NEWTEXTMETRICEXW ntm;
3884 DWORD type;
3885 FONTSIGNATURE fs;
3886 CHARSETINFO csi;
3887 LOGFONTW lf;
3888 int i;
3890 if (!plf)
3892 lf.lfCharSet = DEFAULT_CHARSET;
3893 lf.lfPitchAndFamily = 0;
3894 lf.lfFaceName[0] = 0;
3895 plf = &lf;
3898 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3900 EnterCriticalSection( &freetype_cs );
3901 if(plf->lfFaceName[0]) {
3902 FontSubst *psub;
3903 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3905 if(psub) {
3906 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3907 debugstr_w(psub->to.name));
3908 lf = *plf;
3909 strcpyW(lf.lfFaceName, psub->to.name);
3910 plf = &lf;
3913 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3914 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3915 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3916 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3917 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3918 GetEnumStructs(face, &elf, &ntm, &type);
3919 for(i = 0; i < 32; i++) {
3920 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3921 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3922 strcpyW(elf.elfScript, OEM_DOSW);
3923 i = 32; /* break out of loop */
3924 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3925 continue;
3926 else {
3927 fs.fsCsb[0] = 1L << i;
3928 fs.fsCsb[1] = 0;
3929 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3930 TCI_SRCFONTSIG))
3931 csi.ciCharset = DEFAULT_CHARSET;
3932 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3933 if(csi.ciCharset != DEFAULT_CHARSET) {
3934 elf.elfLogFont.lfCharSet =
3935 ntm.ntmTm.tmCharSet = csi.ciCharset;
3936 if(ElfScriptsW[i])
3937 strcpyW(elf.elfScript, ElfScriptsW[i]);
3938 else
3939 FIXME("Unknown elfscript for bit %d\n", i);
3942 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3943 debugstr_w(elf.elfLogFont.lfFaceName),
3944 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3945 csi.ciCharset, type, debugstr_w(elf.elfScript),
3946 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3947 ntm.ntmTm.ntmFlags);
3948 /* release section before callback (FIXME) */
3949 LeaveCriticalSection( &freetype_cs );
3950 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3951 EnterCriticalSection( &freetype_cs );
3956 } else {
3957 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3958 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3959 face_elem_ptr = list_head(&family->faces);
3960 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3961 GetEnumStructs(face, &elf, &ntm, &type);
3962 for(i = 0; i < 32; i++) {
3963 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3964 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3965 strcpyW(elf.elfScript, OEM_DOSW);
3966 i = 32; /* break out of loop */
3967 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3968 continue;
3969 else {
3970 fs.fsCsb[0] = 1L << i;
3971 fs.fsCsb[1] = 0;
3972 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3973 TCI_SRCFONTSIG))
3974 csi.ciCharset = DEFAULT_CHARSET;
3975 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3976 if(csi.ciCharset != DEFAULT_CHARSET) {
3977 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3978 csi.ciCharset;
3979 if(ElfScriptsW[i])
3980 strcpyW(elf.elfScript, ElfScriptsW[i]);
3981 else
3982 FIXME("Unknown elfscript for bit %d\n", i);
3985 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3986 debugstr_w(elf.elfLogFont.lfFaceName),
3987 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3988 csi.ciCharset, type, debugstr_w(elf.elfScript),
3989 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3990 ntm.ntmTm.ntmFlags);
3991 /* release section before callback (FIXME) */
3992 LeaveCriticalSection( &freetype_cs );
3993 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3994 EnterCriticalSection( &freetype_cs );
3998 LeaveCriticalSection( &freetype_cs );
3999 return 1;
4002 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4004 pt->x.value = vec->x >> 6;
4005 pt->x.fract = (vec->x & 0x3f) << 10;
4006 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4007 pt->y.value = vec->y >> 6;
4008 pt->y.fract = (vec->y & 0x3f) << 10;
4009 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4010 return;
4013 /***************************************************
4014 * According to the MSDN documentation on WideCharToMultiByte,
4015 * certain codepages cannot set the default_used parameter.
4016 * This returns TRUE if the codepage can set that parameter, false else
4017 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4019 static BOOL codepage_sets_default_used(UINT codepage)
4021 switch (codepage)
4023 case CP_UTF7:
4024 case CP_UTF8:
4025 case CP_SYMBOL:
4026 return FALSE;
4027 default:
4028 return TRUE;
4033 * GSUB Table handling functions
4036 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4038 const GSUB_CoverageFormat1* cf1;
4040 cf1 = (GSUB_CoverageFormat1*)table;
4042 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4044 int count = GET_BE_WORD(cf1->GlyphCount);
4045 int i;
4046 TRACE("Coverage Format 1, %i glyphs\n",count);
4047 for (i = 0; i < count; i++)
4048 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4049 return i;
4050 return -1;
4052 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4054 const GSUB_CoverageFormat2* cf2;
4055 int i;
4056 int count;
4057 cf2 = (GSUB_CoverageFormat2*)cf1;
4059 count = GET_BE_WORD(cf2->RangeCount);
4060 TRACE("Coverage Format 2, %i ranges\n",count);
4061 for (i = 0; i < count; i++)
4063 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4064 return -1;
4065 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4066 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4068 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4069 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4072 return -1;
4074 else
4075 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4077 return -1;
4080 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4082 const GSUB_ScriptList *script;
4083 const GSUB_Script *deflt = NULL;
4084 int i;
4085 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4087 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4088 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4090 const GSUB_Script *scr;
4091 int offset;
4093 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4094 scr = (GSUB_Script*)((LPBYTE)script + offset);
4096 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4097 return scr;
4098 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4099 deflt = scr;
4101 return deflt;
4104 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4106 int i;
4107 int offset;
4108 const GSUB_LangSys *Lang;
4110 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4112 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4114 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4115 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4117 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4118 return Lang;
4120 offset = GET_BE_WORD(script->DefaultLangSys);
4121 if (offset)
4123 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4124 return Lang;
4126 return NULL;
4129 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4131 int i;
4132 const GSUB_FeatureList *feature;
4133 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4135 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4136 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4138 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4139 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4141 const GSUB_Feature *feat;
4142 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4143 return feat;
4146 return NULL;
4149 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4151 int i;
4152 int offset;
4153 const GSUB_LookupList *lookup;
4154 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4156 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4157 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4159 const GSUB_LookupTable *look;
4160 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4161 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4162 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4163 if (GET_BE_WORD(look->LookupType) != 1)
4164 FIXME("We only handle SubType 1\n");
4165 else
4167 int j;
4169 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4171 const GSUB_SingleSubstFormat1 *ssf1;
4172 offset = GET_BE_WORD(look->SubTable[j]);
4173 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4174 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4176 int offset = GET_BE_WORD(ssf1->Coverage);
4177 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4178 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4180 TRACE(" Glyph 0x%x ->",glyph);
4181 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4182 TRACE(" 0x%x\n",glyph);
4185 else
4187 const GSUB_SingleSubstFormat2 *ssf2;
4188 INT index;
4189 INT offset;
4191 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4192 offset = GET_BE_WORD(ssf1->Coverage);
4193 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4194 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4195 TRACE(" Coverage index %i\n",index);
4196 if (index != -1)
4198 TRACE(" Glyph is 0x%x ->",glyph);
4199 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4200 TRACE("0x%x\n",glyph);
4206 return glyph;
4209 static const char* get_opentype_script(const GdiFont *font)
4212 * I am not sure if this is the correct way to generate our script tag
4215 switch (font->charset)
4217 case ANSI_CHARSET: return "latn";
4218 case BALTIC_CHARSET: return "latn"; /* ?? */
4219 case CHINESEBIG5_CHARSET: return "hani";
4220 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4221 case GB2312_CHARSET: return "hani";
4222 case GREEK_CHARSET: return "grek";
4223 case HANGUL_CHARSET: return "hang";
4224 case RUSSIAN_CHARSET: return "cyrl";
4225 case SHIFTJIS_CHARSET: return "kana";
4226 case TURKISH_CHARSET: return "latn"; /* ?? */
4227 case VIETNAMESE_CHARSET: return "latn";
4228 case JOHAB_CHARSET: return "latn"; /* ?? */
4229 case ARABIC_CHARSET: return "arab";
4230 case HEBREW_CHARSET: return "hebr";
4231 case THAI_CHARSET: return "thai";
4232 default: return "latn";
4236 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4238 const GSUB_Header *header;
4239 const GSUB_Script *script;
4240 const GSUB_LangSys *language;
4241 const GSUB_Feature *feature;
4243 if (!font->GSUB_Table)
4244 return glyph;
4246 header = font->GSUB_Table;
4248 script = GSUB_get_script_table(header, get_opentype_script(font));
4249 if (!script)
4251 TRACE("Script not found\n");
4252 return glyph;
4254 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4255 if (!language)
4257 TRACE("Language not found\n");
4258 return glyph;
4260 feature = GSUB_get_feature(header, language, "vrt2");
4261 if (!feature)
4262 feature = GSUB_get_feature(header, language, "vert");
4263 if (!feature)
4265 TRACE("vrt2/vert feature not found\n");
4266 return glyph;
4268 return GSUB_apply_feature(header, feature, glyph);
4271 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4273 FT_UInt glyphId;
4275 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4276 WCHAR wc = (WCHAR)glyph;
4277 BOOL default_used;
4278 BOOL *default_used_pointer;
4279 FT_UInt ret;
4280 char buf;
4281 default_used_pointer = NULL;
4282 default_used = FALSE;
4283 if (codepage_sets_default_used(font->codepage))
4284 default_used_pointer = &default_used;
4285 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4286 ret = 0;
4287 else
4288 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4289 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4290 return get_GSUB_vert_glyph(font,ret);
4293 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4294 glyph = glyph + 0xf000;
4295 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4296 return get_GSUB_vert_glyph(font,glyphId);
4299 /*************************************************************
4300 * WineEngGetGlyphIndices
4303 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4304 LPWORD pgi, DWORD flags)
4306 int i;
4307 int default_char = -1;
4309 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4311 for(i = 0; i < count; i++)
4313 pgi[i] = get_glyph_index(font, lpstr[i]);
4314 if (pgi[i] == 0)
4316 if (default_char == -1)
4318 if (FT_IS_SFNT(font->ft_face))
4320 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4321 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4323 else
4325 TEXTMETRICW textm;
4326 WineEngGetTextMetrics(font, &textm);
4327 default_char = textm.tmDefaultChar;
4330 pgi[i] = default_char;
4333 return count;
4336 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4338 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4339 return !memcmp(matrix, &identity, sizeof(FMAT2));
4342 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4344 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4345 return !memcmp(matrix, &identity, sizeof(MAT2));
4348 /*************************************************************
4349 * WineEngGetGlyphOutline
4351 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4352 * except that the first parameter is the HWINEENGFONT of the font in
4353 * question rather than an HDC.
4356 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4357 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4358 const MAT2* lpmat)
4360 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4361 FT_Face ft_face = incoming_font->ft_face;
4362 GdiFont *font = incoming_font;
4363 FT_UInt glyph_index;
4364 DWORD width, height, pitch, needed = 0;
4365 FT_Bitmap ft_bitmap;
4366 FT_Error err;
4367 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4368 FT_Angle angle = 0;
4369 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4370 double widthRatio = 1.0;
4371 FT_Matrix transMat = identityMat;
4372 FT_Matrix transMatUnrotated;
4373 BOOL needsTransform = FALSE;
4374 BOOL tategaki = (font->GSUB_Table != NULL);
4375 UINT original_index;
4377 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4378 buflen, buf, lpmat);
4380 TRACE("font transform %f %f %f %f\n",
4381 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4382 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4384 EnterCriticalSection( &freetype_cs );
4386 if(format & GGO_GLYPH_INDEX) {
4387 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4388 original_index = glyph;
4389 format &= ~GGO_GLYPH_INDEX;
4390 } else {
4391 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4392 ft_face = font->ft_face;
4393 original_index = glyph_index;
4396 if(format & GGO_UNHINTED) {
4397 load_flags |= FT_LOAD_NO_HINTING;
4398 format &= ~GGO_UNHINTED;
4401 /* tategaki never appears to happen to lower glyph index */
4402 if (glyph_index < TATEGAKI_LOWER_BOUND )
4403 tategaki = FALSE;
4405 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4406 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4407 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4408 font->gmsize * sizeof(GM*));
4409 } else {
4410 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4411 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4413 *lpgm = FONT_GM(font,original_index)->gm;
4414 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4415 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4416 lpgm->gmCellIncX, lpgm->gmCellIncY);
4417 LeaveCriticalSection( &freetype_cs );
4418 return 1; /* FIXME */
4422 if (!font->gm[original_index / GM_BLOCK_SIZE])
4423 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4425 /* Scaling factor */
4426 if (font->aveWidth)
4428 TEXTMETRICW tm;
4430 WineEngGetTextMetrics(font, &tm);
4432 widthRatio = (double)font->aveWidth;
4433 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4435 else
4436 widthRatio = font->scale_y;
4438 /* Scaling transform */
4439 if (widthRatio != 1.0 || font->scale_y != 1.0)
4441 FT_Matrix scaleMat;
4442 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4443 scaleMat.xy = 0;
4444 scaleMat.yx = 0;
4445 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4447 pFT_Matrix_Multiply(&scaleMat, &transMat);
4448 needsTransform = TRUE;
4451 /* Slant transform */
4452 if (font->fake_italic) {
4453 FT_Matrix slantMat;
4455 slantMat.xx = (1 << 16);
4456 slantMat.xy = ((1 << 16) >> 2);
4457 slantMat.yx = 0;
4458 slantMat.yy = (1 << 16);
4459 pFT_Matrix_Multiply(&slantMat, &transMat);
4460 needsTransform = TRUE;
4463 /* Rotation transform */
4464 transMatUnrotated = transMat;
4465 if(font->orientation && !tategaki) {
4466 FT_Matrix rotationMat;
4467 FT_Vector vecAngle;
4468 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4469 pFT_Vector_Unit(&vecAngle, angle);
4470 rotationMat.xx = vecAngle.x;
4471 rotationMat.xy = -vecAngle.y;
4472 rotationMat.yx = -rotationMat.xy;
4473 rotationMat.yy = rotationMat.xx;
4475 pFT_Matrix_Multiply(&rotationMat, &transMat);
4476 needsTransform = TRUE;
4479 /* World transform */
4480 if (!is_identity_FMAT2(&font->font_desc.matrix))
4482 FT_Matrix worldMat;
4483 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4484 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4485 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4486 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4487 pFT_Matrix_Multiply(&worldMat, &transMat);
4488 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4489 needsTransform = TRUE;
4492 /* Extra transformation specified by caller */
4493 if (lpmat && !is_identity_MAT2(lpmat))
4495 FT_Matrix extraMat;
4496 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4497 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4498 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4499 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4500 pFT_Matrix_Multiply(&extraMat, &transMat);
4501 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4502 needsTransform = TRUE;
4505 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4506 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4507 format == GGO_GRAY8_BITMAP))
4509 load_flags |= FT_LOAD_NO_BITMAP;
4512 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4514 if(err) {
4515 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4516 LeaveCriticalSection( &freetype_cs );
4517 return GDI_ERROR;
4520 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4521 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4523 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4524 lsb = left >> 6;
4525 bbx = (right - left) >> 6;
4527 if(!needsTransform) {
4528 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4529 bottom = (ft_face->glyph->metrics.horiBearingY -
4530 ft_face->glyph->metrics.height) & -64;
4531 lpgm->gmCellIncX = adv;
4532 lpgm->gmCellIncY = 0;
4533 } else {
4534 INT xc, yc;
4535 FT_Vector vec;
4536 for(xc = 0; xc < 2; xc++) {
4537 for(yc = 0; yc < 2; yc++) {
4538 vec.x = (ft_face->glyph->metrics.horiBearingX +
4539 xc * ft_face->glyph->metrics.width);
4540 vec.y = ft_face->glyph->metrics.horiBearingY -
4541 yc * ft_face->glyph->metrics.height;
4542 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4543 pFT_Vector_Transform(&vec, &transMat);
4544 if(xc == 0 && yc == 0) {
4545 left = right = vec.x;
4546 top = bottom = vec.y;
4547 } else {
4548 if(vec.x < left) left = vec.x;
4549 else if(vec.x > right) right = vec.x;
4550 if(vec.y < bottom) bottom = vec.y;
4551 else if(vec.y > top) top = vec.y;
4555 left = left & -64;
4556 right = (right + 63) & -64;
4557 bottom = bottom & -64;
4558 top = (top + 63) & -64;
4560 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4561 vec.x = ft_face->glyph->metrics.horiAdvance;
4562 vec.y = 0;
4563 pFT_Vector_Transform(&vec, &transMat);
4564 lpgm->gmCellIncX = (vec.x+63) >> 6;
4565 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4567 vec.x = ft_face->glyph->metrics.horiAdvance;
4568 vec.y = 0;
4569 pFT_Vector_Transform(&vec, &transMatUnrotated);
4570 adv = (vec.x+63) >> 6;
4572 lpgm->gmBlackBoxX = (right - left) >> 6;
4573 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4574 lpgm->gmptGlyphOrigin.x = left >> 6;
4575 lpgm->gmptGlyphOrigin.y = top >> 6;
4577 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4578 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4579 lpgm->gmCellIncX, lpgm->gmCellIncY);
4581 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4582 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4584 FONT_GM(font,original_index)->gm = *lpgm;
4585 FONT_GM(font,original_index)->adv = adv;
4586 FONT_GM(font,original_index)->lsb = lsb;
4587 FONT_GM(font,original_index)->bbx = bbx;
4588 FONT_GM(font,original_index)->init = TRUE;
4591 if(format == GGO_METRICS)
4593 LeaveCriticalSection( &freetype_cs );
4594 return 1; /* FIXME */
4597 if(ft_face->glyph->format != ft_glyph_format_outline &&
4598 (needsTransform || format == GGO_NATIVE || format == GGO_BEZIER ||
4599 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4600 format == GGO_GRAY8_BITMAP))
4602 TRACE("loaded a bitmap\n");
4603 LeaveCriticalSection( &freetype_cs );
4604 return GDI_ERROR;
4607 switch(format) {
4608 case GGO_BITMAP:
4609 width = lpgm->gmBlackBoxX;
4610 height = lpgm->gmBlackBoxY;
4611 pitch = ((width + 31) >> 5) << 2;
4612 needed = pitch * height;
4614 if(!buf || !buflen) break;
4616 switch(ft_face->glyph->format) {
4617 case ft_glyph_format_bitmap:
4619 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4620 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4621 INT h = ft_face->glyph->bitmap.rows;
4622 while(h--) {
4623 memcpy(dst, src, w);
4624 src += ft_face->glyph->bitmap.pitch;
4625 dst += pitch;
4627 break;
4630 case ft_glyph_format_outline:
4631 ft_bitmap.width = width;
4632 ft_bitmap.rows = height;
4633 ft_bitmap.pitch = pitch;
4634 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4635 ft_bitmap.buffer = buf;
4637 if(needsTransform)
4638 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4640 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4642 /* Note: FreeType will only set 'black' bits for us. */
4643 memset(buf, 0, needed);
4644 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4645 break;
4647 default:
4648 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4649 LeaveCriticalSection( &freetype_cs );
4650 return GDI_ERROR;
4652 break;
4654 case GGO_GRAY2_BITMAP:
4655 case GGO_GRAY4_BITMAP:
4656 case GGO_GRAY8_BITMAP:
4657 case WINE_GGO_GRAY16_BITMAP:
4659 unsigned int mult, row, col;
4660 BYTE *start, *ptr;
4662 width = lpgm->gmBlackBoxX;
4663 height = lpgm->gmBlackBoxY;
4664 pitch = (width + 3) / 4 * 4;
4665 needed = pitch * height;
4667 if(!buf || !buflen) break;
4669 switch(ft_face->glyph->format) {
4670 case ft_glyph_format_bitmap:
4672 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4673 INT h = ft_face->glyph->bitmap.rows;
4674 INT x;
4675 while(h--) {
4676 for(x = 0; x < pitch; x++)
4678 if(x < ft_face->glyph->bitmap.width)
4679 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4680 else
4681 dst[x] = 0;
4683 src += ft_face->glyph->bitmap.pitch;
4684 dst += pitch;
4686 LeaveCriticalSection( &freetype_cs );
4687 return needed;
4689 case ft_glyph_format_outline:
4691 ft_bitmap.width = width;
4692 ft_bitmap.rows = height;
4693 ft_bitmap.pitch = pitch;
4694 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4695 ft_bitmap.buffer = buf;
4697 if(needsTransform)
4698 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4700 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4702 memset(ft_bitmap.buffer, 0, buflen);
4704 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4706 if(format == GGO_GRAY2_BITMAP)
4707 mult = 4;
4708 else if(format == GGO_GRAY4_BITMAP)
4709 mult = 16;
4710 else if(format == GGO_GRAY8_BITMAP)
4711 mult = 64;
4712 else /* format == WINE_GGO_GRAY16_BITMAP */
4714 LeaveCriticalSection( &freetype_cs );
4715 return needed;
4717 break;
4719 default:
4720 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4721 LeaveCriticalSection( &freetype_cs );
4722 return GDI_ERROR;
4725 start = buf;
4726 for(row = 0; row < height; row++) {
4727 ptr = start;
4728 for(col = 0; col < width; col++, ptr++) {
4729 *ptr = (((int)*ptr) * mult + 128) / 256;
4731 start += pitch;
4733 break;
4736 case WINE_GGO_HRGB_BITMAP:
4737 case WINE_GGO_HBGR_BITMAP:
4738 case WINE_GGO_VRGB_BITMAP:
4739 case WINE_GGO_VBGR_BITMAP:
4740 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4742 switch (ft_face->glyph->format)
4744 case FT_GLYPH_FORMAT_BITMAP:
4746 BYTE *src, *dst;
4747 INT src_pitch, x;
4749 width = lpgm->gmBlackBoxX;
4750 height = lpgm->gmBlackBoxY;
4751 pitch = width * 4;
4752 needed = pitch * height;
4754 if (!buf || !buflen) break;
4756 memset(buf, 0, buflen);
4757 dst = buf;
4758 src = ft_face->glyph->bitmap.buffer;
4759 src_pitch = ft_face->glyph->bitmap.pitch;
4761 while ( height-- )
4763 for (x = 0; x < width; x++)
4765 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4766 ((unsigned int *)dst)[x] = ~0u;
4768 src += src_pitch;
4769 dst += pitch;
4772 break;
4775 case FT_GLYPH_FORMAT_OUTLINE:
4777 unsigned int *dst;
4778 BYTE *src;
4779 INT x, src_pitch, rgb_interval, hmul, vmul;
4780 BOOL rgb;
4781 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4782 FT_Render_Mode render_mode =
4783 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4784 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4786 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4788 if ( render_mode == FT_RENDER_MODE_LCD)
4790 lpgm->gmBlackBoxX += 2;
4791 lpgm->gmptGlyphOrigin.x -= 1;
4793 else
4795 lpgm->gmBlackBoxY += 2;
4796 lpgm->gmptGlyphOrigin.y += 1;
4800 width = lpgm->gmBlackBoxX;
4801 height = lpgm->gmBlackBoxY;
4802 pitch = width * 4;
4803 needed = pitch * height;
4805 if (!buf || !buflen) break;
4807 memset(buf, 0, buflen);
4808 dst = (unsigned int *)buf;
4809 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
4811 if ( needsTransform )
4812 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
4813 pFT_Outline_Translate (&ft_face->glyph->outline, -left, -bottom );
4814 if ( pFT_Library_SetLcdFilter )
4815 pFT_Library_SetLcdFilter( library, lcdfilter );
4816 pFT_Render_Glyph (ft_face->glyph, render_mode);
4818 src = ft_face->glyph->bitmap.buffer;
4819 src_pitch = ft_face->glyph->bitmap.pitch;
4820 if ( render_mode == FT_RENDER_MODE_LCD)
4822 rgb_interval = 1;
4823 hmul = 3;
4824 vmul = 1;
4826 else
4828 rgb_interval = src_pitch;
4829 hmul = 1;
4830 vmul = 3;
4833 while ( height-- )
4835 for ( x = 0; x < width; x++ )
4837 if ( rgb )
4839 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
4840 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4841 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
4842 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4844 else
4846 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
4847 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4848 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
4849 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4852 src += src_pitch * vmul;
4853 dst += pitch / 4;
4856 break;
4859 default:
4860 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
4861 LeaveCriticalSection ( &freetype_cs );
4862 return GDI_ERROR;
4865 break;
4867 #else
4868 LeaveCriticalSection( &freetype_cs );
4869 return GDI_ERROR;
4870 #endif
4872 case GGO_NATIVE:
4874 int contour, point = 0, first_pt;
4875 FT_Outline *outline = &ft_face->glyph->outline;
4876 TTPOLYGONHEADER *pph;
4877 TTPOLYCURVE *ppc;
4878 DWORD pph_start, cpfx, type;
4880 if(buflen == 0) buf = NULL;
4882 if (needsTransform && buf) {
4883 pFT_Outline_Transform(outline, &transMat);
4886 for(contour = 0; contour < outline->n_contours; contour++) {
4887 pph_start = needed;
4888 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4889 first_pt = point;
4890 if(buf) {
4891 pph->dwType = TT_POLYGON_TYPE;
4892 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4894 needed += sizeof(*pph);
4895 point++;
4896 while(point <= outline->contours[contour]) {
4897 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4898 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4899 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4900 cpfx = 0;
4901 do {
4902 if(buf)
4903 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4904 cpfx++;
4905 point++;
4906 } while(point <= outline->contours[contour] &&
4907 (outline->tags[point] & FT_Curve_Tag_On) ==
4908 (outline->tags[point-1] & FT_Curve_Tag_On));
4909 /* At the end of a contour Windows adds the start point, but
4910 only for Beziers */
4911 if(point > outline->contours[contour] &&
4912 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4913 if(buf)
4914 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4915 cpfx++;
4916 } else if(point <= outline->contours[contour] &&
4917 outline->tags[point] & FT_Curve_Tag_On) {
4918 /* add closing pt for bezier */
4919 if(buf)
4920 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4921 cpfx++;
4922 point++;
4924 if(buf) {
4925 ppc->wType = type;
4926 ppc->cpfx = cpfx;
4928 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4930 if(buf)
4931 pph->cb = needed - pph_start;
4933 break;
4935 case GGO_BEZIER:
4937 /* Convert the quadratic Beziers to cubic Beziers.
4938 The parametric eqn for a cubic Bezier is, from PLRM:
4939 r(t) = at^3 + bt^2 + ct + r0
4940 with the control points:
4941 r1 = r0 + c/3
4942 r2 = r1 + (c + b)/3
4943 r3 = r0 + c + b + a
4945 A quadratic Beizer has the form:
4946 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4948 So equating powers of t leads to:
4949 r1 = 2/3 p1 + 1/3 p0
4950 r2 = 2/3 p1 + 1/3 p2
4951 and of course r0 = p0, r3 = p2
4954 int contour, point = 0, first_pt;
4955 FT_Outline *outline = &ft_face->glyph->outline;
4956 TTPOLYGONHEADER *pph;
4957 TTPOLYCURVE *ppc;
4958 DWORD pph_start, cpfx, type;
4959 FT_Vector cubic_control[4];
4960 if(buflen == 0) buf = NULL;
4962 if (needsTransform && buf) {
4963 pFT_Outline_Transform(outline, &transMat);
4966 for(contour = 0; contour < outline->n_contours; contour++) {
4967 pph_start = needed;
4968 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4969 first_pt = point;
4970 if(buf) {
4971 pph->dwType = TT_POLYGON_TYPE;
4972 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4974 needed += sizeof(*pph);
4975 point++;
4976 while(point <= outline->contours[contour]) {
4977 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4978 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4979 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4980 cpfx = 0;
4981 do {
4982 if(type == TT_PRIM_LINE) {
4983 if(buf)
4984 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4985 cpfx++;
4986 point++;
4987 } else {
4988 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4989 so cpfx = 3n */
4991 /* FIXME: Possible optimization in endpoint calculation
4992 if there are two consecutive curves */
4993 cubic_control[0] = outline->points[point-1];
4994 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4995 cubic_control[0].x += outline->points[point].x + 1;
4996 cubic_control[0].y += outline->points[point].y + 1;
4997 cubic_control[0].x >>= 1;
4998 cubic_control[0].y >>= 1;
5000 if(point+1 > outline->contours[contour])
5001 cubic_control[3] = outline->points[first_pt];
5002 else {
5003 cubic_control[3] = outline->points[point+1];
5004 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5005 cubic_control[3].x += outline->points[point].x + 1;
5006 cubic_control[3].y += outline->points[point].y + 1;
5007 cubic_control[3].x >>= 1;
5008 cubic_control[3].y >>= 1;
5011 /* r1 = 1/3 p0 + 2/3 p1
5012 r2 = 1/3 p2 + 2/3 p1 */
5013 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5014 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5015 cubic_control[2] = cubic_control[1];
5016 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5017 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5018 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5019 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5020 if(buf) {
5021 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5022 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5023 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5025 cpfx += 3;
5026 point++;
5028 } while(point <= outline->contours[contour] &&
5029 (outline->tags[point] & FT_Curve_Tag_On) ==
5030 (outline->tags[point-1] & FT_Curve_Tag_On));
5031 /* At the end of a contour Windows adds the start point,
5032 but only for Beziers and we've already done that.
5034 if(point <= outline->contours[contour] &&
5035 outline->tags[point] & FT_Curve_Tag_On) {
5036 /* This is the closing pt of a bezier, but we've already
5037 added it, so just inc point and carry on */
5038 point++;
5040 if(buf) {
5041 ppc->wType = type;
5042 ppc->cpfx = cpfx;
5044 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5046 if(buf)
5047 pph->cb = needed - pph_start;
5049 break;
5052 default:
5053 FIXME("Unsupported format %d\n", format);
5054 LeaveCriticalSection( &freetype_cs );
5055 return GDI_ERROR;
5057 LeaveCriticalSection( &freetype_cs );
5058 return needed;
5061 static BOOL get_bitmap_text_metrics(GdiFont *font)
5063 FT_Face ft_face = font->ft_face;
5064 #ifdef HAVE_FREETYPE_FTWINFNT_H
5065 FT_WinFNT_HeaderRec winfnt_header;
5066 #endif
5067 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5068 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5069 font->potm->otmSize = size;
5071 #define TM font->potm->otmTextMetrics
5072 #ifdef HAVE_FREETYPE_FTWINFNT_H
5073 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5075 TM.tmHeight = winfnt_header.pixel_height;
5076 TM.tmAscent = winfnt_header.ascent;
5077 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5078 TM.tmInternalLeading = winfnt_header.internal_leading;
5079 TM.tmExternalLeading = winfnt_header.external_leading;
5080 TM.tmAveCharWidth = winfnt_header.avg_width;
5081 TM.tmMaxCharWidth = winfnt_header.max_width;
5082 TM.tmWeight = winfnt_header.weight;
5083 TM.tmOverhang = 0;
5084 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5085 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5086 TM.tmFirstChar = winfnt_header.first_char;
5087 TM.tmLastChar = winfnt_header.last_char;
5088 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5089 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5090 TM.tmItalic = winfnt_header.italic;
5091 TM.tmUnderlined = font->underline;
5092 TM.tmStruckOut = font->strikeout;
5093 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5094 TM.tmCharSet = winfnt_header.charset;
5096 else
5097 #endif
5099 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5100 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5101 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5102 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5103 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5104 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5105 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5106 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5107 TM.tmOverhang = 0;
5108 TM.tmDigitizedAspectX = 96; /* FIXME */
5109 TM.tmDigitizedAspectY = 96; /* FIXME */
5110 TM.tmFirstChar = 1;
5111 TM.tmLastChar = 255;
5112 TM.tmDefaultChar = 32;
5113 TM.tmBreakChar = 32;
5114 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5115 TM.tmUnderlined = font->underline;
5116 TM.tmStruckOut = font->strikeout;
5117 /* NB inverted meaning of TMPF_FIXED_PITCH */
5118 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5119 TM.tmCharSet = font->charset;
5121 #undef TM
5123 return TRUE;
5127 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5129 double scale_x, scale_y;
5131 if (font->aveWidth)
5133 scale_x = (double)font->aveWidth;
5134 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5136 else
5137 scale_x = font->scale_y;
5139 scale_x *= fabs(font->font_desc.matrix.eM11);
5140 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5142 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5143 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5145 SCALE_Y(ptm->tmHeight);
5146 SCALE_Y(ptm->tmAscent);
5147 SCALE_Y(ptm->tmDescent);
5148 SCALE_Y(ptm->tmInternalLeading);
5149 SCALE_Y(ptm->tmExternalLeading);
5150 SCALE_Y(ptm->tmOverhang);
5152 SCALE_X(ptm->tmAveCharWidth);
5153 SCALE_X(ptm->tmMaxCharWidth);
5155 #undef SCALE_X
5156 #undef SCALE_Y
5159 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5161 double scale_x, scale_y;
5163 if (font->aveWidth)
5165 scale_x = (double)font->aveWidth;
5166 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5168 else
5169 scale_x = font->scale_y;
5171 scale_x *= fabs(font->font_desc.matrix.eM11);
5172 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5174 scale_font_metrics(font, &potm->otmTextMetrics);
5176 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5177 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5179 SCALE_Y(potm->otmAscent);
5180 SCALE_Y(potm->otmDescent);
5181 SCALE_Y(potm->otmLineGap);
5182 SCALE_Y(potm->otmsCapEmHeight);
5183 SCALE_Y(potm->otmsXHeight);
5184 SCALE_Y(potm->otmrcFontBox.top);
5185 SCALE_Y(potm->otmrcFontBox.bottom);
5186 SCALE_X(potm->otmrcFontBox.left);
5187 SCALE_X(potm->otmrcFontBox.right);
5188 SCALE_Y(potm->otmMacAscent);
5189 SCALE_Y(potm->otmMacDescent);
5190 SCALE_Y(potm->otmMacLineGap);
5191 SCALE_X(potm->otmptSubscriptSize.x);
5192 SCALE_Y(potm->otmptSubscriptSize.y);
5193 SCALE_X(potm->otmptSubscriptOffset.x);
5194 SCALE_Y(potm->otmptSubscriptOffset.y);
5195 SCALE_X(potm->otmptSuperscriptSize.x);
5196 SCALE_Y(potm->otmptSuperscriptSize.y);
5197 SCALE_X(potm->otmptSuperscriptOffset.x);
5198 SCALE_Y(potm->otmptSuperscriptOffset.y);
5199 SCALE_Y(potm->otmsStrikeoutSize);
5200 SCALE_Y(potm->otmsStrikeoutPosition);
5201 SCALE_Y(potm->otmsUnderscoreSize);
5202 SCALE_Y(potm->otmsUnderscorePosition);
5204 #undef SCALE_X
5205 #undef SCALE_Y
5208 /*************************************************************
5209 * WineEngGetTextMetrics
5212 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5214 EnterCriticalSection( &freetype_cs );
5215 if(!font->potm) {
5216 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5217 if(!get_bitmap_text_metrics(font))
5219 LeaveCriticalSection( &freetype_cs );
5220 return FALSE;
5223 if(!font->potm)
5225 LeaveCriticalSection( &freetype_cs );
5226 return FALSE;
5228 *ptm = font->potm->otmTextMetrics;
5229 scale_font_metrics(font, ptm);
5230 LeaveCriticalSection( &freetype_cs );
5231 return TRUE;
5235 /*************************************************************
5236 * WineEngGetOutlineTextMetrics
5239 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5240 OUTLINETEXTMETRICW *potm)
5242 FT_Face ft_face = font->ft_face;
5243 UINT needed, lenfam, lensty, ret;
5244 TT_OS2 *pOS2;
5245 TT_HoriHeader *pHori;
5246 TT_Postscript *pPost;
5247 FT_Fixed x_scale, y_scale;
5248 WCHAR *family_nameW, *style_nameW;
5249 static const WCHAR spaceW[] = {' ', '\0'};
5250 char *cp;
5251 INT ascent, descent;
5253 TRACE("font=%p\n", font);
5255 if(!FT_IS_SCALABLE(ft_face))
5256 return 0;
5258 EnterCriticalSection( &freetype_cs );
5260 if(font->potm) {
5261 if(cbSize >= font->potm->otmSize)
5263 memcpy(potm, font->potm, font->potm->otmSize);
5264 scale_outline_font_metrics(font, potm);
5266 LeaveCriticalSection( &freetype_cs );
5267 return font->potm->otmSize;
5271 needed = sizeof(*potm);
5273 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5274 family_nameW = strdupW(font->name);
5276 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5277 * sizeof(WCHAR);
5278 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5279 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5280 style_nameW, lensty/sizeof(WCHAR));
5282 /* These names should be read from the TT name table */
5284 /* length of otmpFamilyName */
5285 needed += lenfam;
5287 /* length of otmpFaceName */
5288 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5289 needed += lenfam; /* just the family name */
5290 } else {
5291 needed += lenfam + lensty; /* family + " " + style */
5294 /* length of otmpStyleName */
5295 needed += lensty;
5297 /* length of otmpFullName */
5298 needed += lenfam + lensty;
5301 x_scale = ft_face->size->metrics.x_scale;
5302 y_scale = ft_face->size->metrics.y_scale;
5304 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5305 if(!pOS2) {
5306 FIXME("Can't find OS/2 table - not TT font?\n");
5307 ret = 0;
5308 goto end;
5311 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5312 if(!pHori) {
5313 FIXME("Can't find HHEA table - not TT font?\n");
5314 ret = 0;
5315 goto end;
5318 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5320 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",
5321 pOS2->usWinAscent, pOS2->usWinDescent,
5322 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5323 ft_face->ascender, ft_face->descender, ft_face->height,
5324 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5325 ft_face->bbox.yMax, ft_face->bbox.yMin);
5327 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5328 font->potm->otmSize = needed;
5330 #define TM font->potm->otmTextMetrics
5332 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5333 ascent = pHori->Ascender;
5334 descent = -pHori->Descender;
5335 } else {
5336 ascent = pOS2->usWinAscent;
5337 descent = pOS2->usWinDescent;
5340 if(font->yMax) {
5341 TM.tmAscent = font->yMax;
5342 TM.tmDescent = -font->yMin;
5343 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5344 } else {
5345 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5346 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5347 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5348 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5351 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5353 /* MSDN says:
5354 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5356 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5357 ((ascent + descent) -
5358 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5360 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5361 if (TM.tmAveCharWidth == 0) {
5362 TM.tmAveCharWidth = 1;
5364 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5365 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5366 TM.tmOverhang = 0;
5367 TM.tmDigitizedAspectX = 300;
5368 TM.tmDigitizedAspectY = 300;
5369 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5370 * symbol range to 0 - f0ff
5372 if (font->charset == SYMBOL_CHARSET)
5374 TM.tmFirstChar = 0;
5375 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5377 else
5379 TM.tmFirstChar = pOS2->usFirstCharIndex;
5380 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5382 TM.tmLastChar = pOS2->usLastCharIndex;
5383 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5384 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5385 TM.tmUnderlined = font->underline;
5386 TM.tmStruckOut = font->strikeout;
5388 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5389 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5390 (pOS2->version == 0xFFFFU ||
5391 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5392 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5393 else
5394 TM.tmPitchAndFamily = 0;
5396 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5397 case PAN_FAMILY_SCRIPT:
5398 TM.tmPitchAndFamily |= FF_SCRIPT;
5399 break;
5400 case PAN_FAMILY_DECORATIVE:
5401 case PAN_FAMILY_PICTORIAL:
5402 TM.tmPitchAndFamily |= FF_DECORATIVE;
5403 break;
5404 case PAN_FAMILY_TEXT_DISPLAY:
5405 if(TM.tmPitchAndFamily == 0) /* fixed */
5406 TM.tmPitchAndFamily = FF_MODERN;
5407 else {
5408 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5409 case PAN_SERIF_NORMAL_SANS:
5410 case PAN_SERIF_OBTUSE_SANS:
5411 case PAN_SERIF_PERP_SANS:
5412 TM.tmPitchAndFamily |= FF_SWISS;
5413 break;
5414 default:
5415 TM.tmPitchAndFamily |= FF_ROMAN;
5418 break;
5419 default:
5420 TM.tmPitchAndFamily |= FF_DONTCARE;
5423 if(FT_IS_SCALABLE(ft_face))
5424 TM.tmPitchAndFamily |= TMPF_VECTOR;
5426 if(FT_IS_SFNT(ft_face))
5428 if (font->ntmFlags & NTM_PS_OPENTYPE)
5429 TM.tmPitchAndFamily |= TMPF_DEVICE;
5430 else
5431 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5434 TM.tmCharSet = font->charset;
5436 font->potm->otmFiller = 0;
5437 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5438 font->potm->otmfsSelection = pOS2->fsSelection;
5439 font->potm->otmfsType = pOS2->fsType;
5440 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5441 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5442 font->potm->otmItalicAngle = 0; /* POST table */
5443 font->potm->otmEMSquare = ft_face->units_per_EM;
5444 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5445 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5446 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5447 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5448 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5449 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5450 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5451 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5452 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5453 font->potm->otmMacAscent = TM.tmAscent;
5454 font->potm->otmMacDescent = -TM.tmDescent;
5455 font->potm->otmMacLineGap = font->potm->otmLineGap;
5456 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5457 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5458 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5459 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5460 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5461 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5462 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5463 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5464 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5465 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5466 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5467 if(!pPost) {
5468 font->potm->otmsUnderscoreSize = 0;
5469 font->potm->otmsUnderscorePosition = 0;
5470 } else {
5471 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5472 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5474 #undef TM
5476 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5477 cp = (char*)font->potm + sizeof(*font->potm);
5478 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5479 strcpyW((WCHAR*)cp, family_nameW);
5480 cp += lenfam;
5481 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5482 strcpyW((WCHAR*)cp, style_nameW);
5483 cp += lensty;
5484 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5485 strcpyW((WCHAR*)cp, family_nameW);
5486 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5487 strcatW((WCHAR*)cp, spaceW);
5488 strcatW((WCHAR*)cp, style_nameW);
5489 cp += lenfam + lensty;
5490 } else
5491 cp += lenfam;
5492 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5493 strcpyW((WCHAR*)cp, family_nameW);
5494 strcatW((WCHAR*)cp, spaceW);
5495 strcatW((WCHAR*)cp, style_nameW);
5496 ret = needed;
5498 if(potm && needed <= cbSize)
5500 memcpy(potm, font->potm, font->potm->otmSize);
5501 scale_outline_font_metrics(font, potm);
5504 end:
5505 HeapFree(GetProcessHeap(), 0, style_nameW);
5506 HeapFree(GetProcessHeap(), 0, family_nameW);
5508 LeaveCriticalSection( &freetype_cs );
5509 return ret;
5512 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5514 HFONTLIST *hfontlist;
5515 child->font = alloc_font();
5516 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5517 if(!child->font->ft_face)
5519 free_font(child->font);
5520 child->font = NULL;
5521 return FALSE;
5524 child->font->font_desc = font->font_desc;
5525 child->font->ntmFlags = child->face->ntmFlags;
5526 child->font->orientation = font->orientation;
5527 child->font->scale_y = font->scale_y;
5528 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5529 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5530 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5531 child->font->base_font = font;
5532 list_add_head(&child_font_list, &child->font->entry);
5533 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5534 return TRUE;
5537 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5539 FT_UInt g;
5540 CHILD_FONT *child_font;
5542 if(font->base_font)
5543 font = font->base_font;
5545 *linked_font = font;
5547 if((*glyph = get_glyph_index(font, c)))
5548 return TRUE;
5550 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5552 if(!child_font->font)
5553 if(!load_child_font(font, child_font))
5554 continue;
5556 if(!child_font->font->ft_face)
5557 continue;
5558 g = get_glyph_index(child_font->font, c);
5559 if(g)
5561 *glyph = g;
5562 *linked_font = child_font->font;
5563 return TRUE;
5566 return FALSE;
5569 /*************************************************************
5570 * WineEngGetCharWidth
5573 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5574 LPINT buffer)
5576 UINT c;
5577 GLYPHMETRICS gm;
5578 FT_UInt glyph_index;
5579 GdiFont *linked_font;
5581 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5583 EnterCriticalSection( &freetype_cs );
5584 for(c = firstChar; c <= lastChar; c++) {
5585 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5586 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5587 &gm, 0, NULL, NULL);
5588 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5590 LeaveCriticalSection( &freetype_cs );
5591 return TRUE;
5594 /*************************************************************
5595 * WineEngGetCharABCWidths
5598 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5599 LPABC buffer)
5601 UINT c;
5602 GLYPHMETRICS gm;
5603 FT_UInt glyph_index;
5604 GdiFont *linked_font;
5606 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5608 if(!FT_IS_SCALABLE(font->ft_face))
5609 return FALSE;
5611 EnterCriticalSection( &freetype_cs );
5613 for(c = firstChar; c <= lastChar; c++) {
5614 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5615 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5616 &gm, 0, NULL, NULL);
5617 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5618 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5619 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5620 FONT_GM(linked_font,glyph_index)->bbx;
5622 LeaveCriticalSection( &freetype_cs );
5623 return TRUE;
5626 /*************************************************************
5627 * WineEngGetCharABCWidthsI
5630 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5631 LPABC buffer)
5633 UINT c;
5634 GLYPHMETRICS gm;
5635 FT_UInt glyph_index;
5636 GdiFont *linked_font;
5638 if(!FT_HAS_HORIZONTAL(font->ft_face))
5639 return FALSE;
5641 EnterCriticalSection( &freetype_cs );
5643 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5644 if (!pgi)
5645 for(c = firstChar; c < firstChar+count; c++) {
5646 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5647 &gm, 0, NULL, NULL);
5648 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5649 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5650 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5651 - FONT_GM(linked_font,c)->bbx;
5653 else
5654 for(c = 0; c < count; c++) {
5655 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5656 &gm, 0, NULL, NULL);
5657 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5658 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5659 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5660 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5663 LeaveCriticalSection( &freetype_cs );
5664 return TRUE;
5667 /*************************************************************
5668 * WineEngGetTextExtentExPoint
5671 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5672 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5674 INT idx;
5675 INT nfit = 0, ext;
5676 GLYPHMETRICS gm;
5677 TEXTMETRICW tm;
5678 FT_UInt glyph_index;
5679 GdiFont *linked_font;
5681 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5682 max_ext, size);
5684 EnterCriticalSection( &freetype_cs );
5686 size->cx = 0;
5687 WineEngGetTextMetrics(font, &tm);
5688 size->cy = tm.tmHeight;
5690 for(idx = 0; idx < count; idx++) {
5691 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5692 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5693 &gm, 0, NULL, NULL);
5694 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5695 ext = size->cx;
5696 if (! pnfit || ext <= max_ext) {
5697 ++nfit;
5698 if (dxs)
5699 dxs[idx] = ext;
5703 if (pnfit)
5704 *pnfit = nfit;
5706 LeaveCriticalSection( &freetype_cs );
5707 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5708 return TRUE;
5711 /*************************************************************
5712 * WineEngGetTextExtentExPointI
5715 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5716 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5718 INT idx;
5719 INT nfit = 0, ext;
5720 GLYPHMETRICS gm;
5721 TEXTMETRICW tm;
5723 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5725 EnterCriticalSection( &freetype_cs );
5727 size->cx = 0;
5728 WineEngGetTextMetrics(font, &tm);
5729 size->cy = tm.tmHeight;
5731 for(idx = 0; idx < count; idx++) {
5732 WineEngGetGlyphOutline(font, indices[idx],
5733 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5734 NULL);
5735 size->cx += FONT_GM(font,indices[idx])->adv;
5736 ext = size->cx;
5737 if (! pnfit || ext <= max_ext) {
5738 ++nfit;
5739 if (dxs)
5740 dxs[idx] = ext;
5744 if (pnfit)
5745 *pnfit = nfit;
5747 LeaveCriticalSection( &freetype_cs );
5748 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5749 return TRUE;
5752 /*************************************************************
5753 * WineEngGetFontData
5756 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5757 DWORD cbData)
5759 FT_Face ft_face = font->ft_face;
5760 FT_ULong len;
5761 FT_Error err;
5763 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5764 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5765 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5767 if(!FT_IS_SFNT(ft_face))
5768 return GDI_ERROR;
5770 if(!buf || !cbData)
5771 len = 0;
5772 else
5773 len = cbData;
5775 if(table) { /* MS tags differ in endianness from FT ones */
5776 table = table >> 24 | table << 24 |
5777 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5780 /* make sure value of len is the value freetype says it needs */
5781 if(buf && len)
5783 FT_ULong needed = 0;
5784 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5785 if( !err && needed < len) len = needed;
5787 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5789 if(err) {
5790 TRACE("Can't find table %c%c%c%c\n",
5791 /* bytes were reversed */
5792 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5793 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5794 return GDI_ERROR;
5796 return len;
5799 /*************************************************************
5800 * WineEngGetTextFace
5803 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5805 INT n = strlenW(font->name) + 1;
5806 if(str) {
5807 lstrcpynW(str, font->name, count);
5808 return min(count, n);
5809 } else
5810 return n;
5813 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5815 if (fs) *fs = font->fs;
5816 return font->charset;
5819 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5821 GdiFont *font = dc->gdiFont, *linked_font;
5822 struct list *first_hfont;
5823 BOOL ret;
5825 EnterCriticalSection( &freetype_cs );
5826 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5827 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5828 if(font == linked_font)
5829 *new_hfont = dc->hFont;
5830 else
5832 first_hfont = list_head(&linked_font->hfontlist);
5833 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5835 LeaveCriticalSection( &freetype_cs );
5836 return ret;
5839 /* Retrieve a list of supported Unicode ranges for a given font.
5840 * Can be called with NULL gs to calculate the buffer size. Returns
5841 * the number of ranges found.
5843 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5845 DWORD num_ranges = 0;
5847 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5849 FT_UInt glyph_code;
5850 FT_ULong char_code, char_code_prev;
5852 glyph_code = 0;
5853 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5855 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5856 face->num_glyphs, glyph_code, char_code);
5858 if (!glyph_code) return 0;
5860 if (gs)
5862 gs->ranges[0].wcLow = (USHORT)char_code;
5863 gs->ranges[0].cGlyphs = 0;
5864 gs->cGlyphsSupported = 0;
5867 num_ranges = 1;
5868 while (glyph_code)
5870 if (char_code < char_code_prev)
5872 ERR("expected increasing char code from FT_Get_Next_Char\n");
5873 return 0;
5875 if (char_code - char_code_prev > 1)
5877 num_ranges++;
5878 if (gs)
5880 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5881 gs->ranges[num_ranges - 1].cGlyphs = 1;
5882 gs->cGlyphsSupported++;
5885 else if (gs)
5887 gs->ranges[num_ranges - 1].cGlyphs++;
5888 gs->cGlyphsSupported++;
5890 char_code_prev = char_code;
5891 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5894 else
5895 FIXME("encoding %u not supported\n", face->charmap->encoding);
5897 return num_ranges;
5900 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5902 DWORD size = 0;
5903 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5905 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5906 if (glyphset)
5908 glyphset->cbThis = size;
5909 glyphset->cRanges = num_ranges;
5911 return size;
5914 /*************************************************************
5915 * FontIsLinked
5917 BOOL WineEngFontIsLinked(GdiFont *font)
5919 BOOL ret;
5920 EnterCriticalSection( &freetype_cs );
5921 ret = !list_empty(&font->child_fonts);
5922 LeaveCriticalSection( &freetype_cs );
5923 return ret;
5926 static BOOL is_hinting_enabled(void)
5928 /* Use the >= 2.2.0 function if available */
5929 if(pFT_Get_TrueType_Engine_Type)
5931 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5932 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5934 #ifdef FT_DRIVER_HAS_HINTER
5935 else
5937 FT_Module mod;
5939 /* otherwise if we've been compiled with < 2.2.0 headers
5940 use the internal macro */
5941 mod = pFT_Get_Module(library, "truetype");
5942 if(mod && FT_DRIVER_HAS_HINTER(mod))
5943 return TRUE;
5945 #endif
5947 return FALSE;
5950 static BOOL is_subpixel_rendering_enabled( void )
5952 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5953 return pFT_Library_SetLcdFilter &&
5954 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
5955 #else
5956 return FALSE;
5957 #endif
5960 /*************************************************************************
5961 * GetRasterizerCaps (GDI32.@)
5963 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5965 static int hinting = -1;
5966 static int subpixel = -1;
5968 if(hinting == -1)
5970 hinting = is_hinting_enabled();
5971 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5974 if ( subpixel == -1 )
5976 subpixel = is_subpixel_rendering_enabled();
5977 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
5980 lprs->nSize = sizeof(RASTERIZER_STATUS);
5981 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5982 if ( subpixel )
5983 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
5984 lprs->nLanguageID = 0;
5985 return TRUE;
5988 /*************************************************************
5989 * WineEngRealizationInfo
5991 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5993 FIXME("(%p, %p): stub!\n", font, info);
5995 info->flags = 1;
5996 if(FT_IS_SCALABLE(font->ft_face))
5997 info->flags |= 2;
5999 info->cache_num = font->cache_num;
6000 info->unknown2 = -1;
6001 return TRUE;
6004 /*************************************************************************
6005 * Kerning support for TrueType fonts
6007 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6009 struct TT_kern_table
6011 USHORT version;
6012 USHORT nTables;
6015 struct TT_kern_subtable
6017 USHORT version;
6018 USHORT length;
6019 union
6021 USHORT word;
6022 struct
6024 USHORT horizontal : 1;
6025 USHORT minimum : 1;
6026 USHORT cross_stream: 1;
6027 USHORT override : 1;
6028 USHORT reserved1 : 4;
6029 USHORT format : 8;
6030 } bits;
6031 } coverage;
6034 struct TT_format0_kern_subtable
6036 USHORT nPairs;
6037 USHORT searchRange;
6038 USHORT entrySelector;
6039 USHORT rangeShift;
6042 struct TT_kern_pair
6044 USHORT left;
6045 USHORT right;
6046 short value;
6049 static DWORD parse_format0_kern_subtable(GdiFont *font,
6050 const struct TT_format0_kern_subtable *tt_f0_ks,
6051 const USHORT *glyph_to_char,
6052 KERNINGPAIR *kern_pair, DWORD cPairs)
6054 USHORT i, nPairs;
6055 const struct TT_kern_pair *tt_kern_pair;
6057 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6059 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6061 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6062 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6063 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6065 if (!kern_pair || !cPairs)
6066 return nPairs;
6068 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6070 nPairs = min(nPairs, cPairs);
6072 for (i = 0; i < nPairs; i++)
6074 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6075 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6076 /* this algorithm appears to better match what Windows does */
6077 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6078 if (kern_pair->iKernAmount < 0)
6080 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6081 kern_pair->iKernAmount -= font->ppem;
6083 else if (kern_pair->iKernAmount > 0)
6085 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6086 kern_pair->iKernAmount += font->ppem;
6088 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6090 TRACE("left %u right %u value %d\n",
6091 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6093 kern_pair++;
6095 TRACE("copied %u entries\n", nPairs);
6096 return nPairs;
6099 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6101 DWORD length;
6102 void *buf;
6103 const struct TT_kern_table *tt_kern_table;
6104 const struct TT_kern_subtable *tt_kern_subtable;
6105 USHORT i, nTables;
6106 USHORT *glyph_to_char;
6108 EnterCriticalSection( &freetype_cs );
6109 if (font->total_kern_pairs != (DWORD)-1)
6111 if (cPairs && kern_pair)
6113 cPairs = min(cPairs, font->total_kern_pairs);
6114 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6115 LeaveCriticalSection( &freetype_cs );
6116 return cPairs;
6118 LeaveCriticalSection( &freetype_cs );
6119 return font->total_kern_pairs;
6122 font->total_kern_pairs = 0;
6124 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6126 if (length == GDI_ERROR)
6128 TRACE("no kerning data in the font\n");
6129 LeaveCriticalSection( &freetype_cs );
6130 return 0;
6133 buf = HeapAlloc(GetProcessHeap(), 0, length);
6134 if (!buf)
6136 WARN("Out of memory\n");
6137 LeaveCriticalSection( &freetype_cs );
6138 return 0;
6141 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6143 /* build a glyph index to char code map */
6144 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6145 if (!glyph_to_char)
6147 WARN("Out of memory allocating a glyph index to char code map\n");
6148 HeapFree(GetProcessHeap(), 0, buf);
6149 LeaveCriticalSection( &freetype_cs );
6150 return 0;
6153 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6155 FT_UInt glyph_code;
6156 FT_ULong char_code;
6158 glyph_code = 0;
6159 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6161 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6162 font->ft_face->num_glyphs, glyph_code, char_code);
6164 while (glyph_code)
6166 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6168 /* FIXME: This doesn't match what Windows does: it does some fancy
6169 * things with duplicate glyph index to char code mappings, while
6170 * we just avoid overriding existing entries.
6172 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6173 glyph_to_char[glyph_code] = (USHORT)char_code;
6175 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6178 else
6180 ULONG n;
6182 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6183 for (n = 0; n <= 65535; n++)
6184 glyph_to_char[n] = (USHORT)n;
6187 tt_kern_table = buf;
6188 nTables = GET_BE_WORD(tt_kern_table->nTables);
6189 TRACE("version %u, nTables %u\n",
6190 GET_BE_WORD(tt_kern_table->version), nTables);
6192 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6194 for (i = 0; i < nTables; i++)
6196 struct TT_kern_subtable tt_kern_subtable_copy;
6198 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6199 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6200 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6202 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6203 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6204 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6206 /* According to the TrueType specification this is the only format
6207 * that will be properly interpreted by Windows and OS/2
6209 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6211 DWORD new_chunk, old_total = font->total_kern_pairs;
6213 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6214 glyph_to_char, NULL, 0);
6215 font->total_kern_pairs += new_chunk;
6217 if (!font->kern_pairs)
6218 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6219 font->total_kern_pairs * sizeof(*font->kern_pairs));
6220 else
6221 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6222 font->total_kern_pairs * sizeof(*font->kern_pairs));
6224 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6225 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6227 else
6228 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6230 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6233 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6234 HeapFree(GetProcessHeap(), 0, buf);
6236 if (cPairs && kern_pair)
6238 cPairs = min(cPairs, font->total_kern_pairs);
6239 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6240 LeaveCriticalSection( &freetype_cs );
6241 return cPairs;
6243 LeaveCriticalSection( &freetype_cs );
6244 return font->total_kern_pairs;
6247 #else /* HAVE_FREETYPE */
6249 /*************************************************************************/
6251 BOOL WineEngInit(void)
6253 return FALSE;
6255 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6257 return NULL;
6259 BOOL WineEngDestroyFontInstance(HFONT hfont)
6261 return FALSE;
6264 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6266 return 1;
6269 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6270 LPWORD pgi, DWORD flags)
6272 return GDI_ERROR;
6275 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6276 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6277 const MAT2* lpmat)
6279 ERR("called but we don't have FreeType\n");
6280 return GDI_ERROR;
6283 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6285 ERR("called but we don't have FreeType\n");
6286 return FALSE;
6289 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6290 OUTLINETEXTMETRICW *potm)
6292 ERR("called but we don't have FreeType\n");
6293 return 0;
6296 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6297 LPINT buffer)
6299 ERR("called but we don't have FreeType\n");
6300 return FALSE;
6303 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6304 LPABC buffer)
6306 ERR("called but we don't have FreeType\n");
6307 return FALSE;
6310 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6311 LPABC buffer)
6313 ERR("called but we don't have FreeType\n");
6314 return FALSE;
6317 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6318 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6320 ERR("called but we don't have FreeType\n");
6321 return FALSE;
6324 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6325 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6327 ERR("called but we don't have FreeType\n");
6328 return FALSE;
6331 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6332 DWORD cbData)
6334 ERR("called but we don't have FreeType\n");
6335 return GDI_ERROR;
6338 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6340 ERR("called but we don't have FreeType\n");
6341 return 0;
6344 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6346 FIXME(":stub\n");
6347 return 1;
6350 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6352 FIXME(":stub\n");
6353 return TRUE;
6356 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6358 FIXME(":stub\n");
6359 return NULL;
6362 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6364 FIXME(":stub\n");
6365 return DEFAULT_CHARSET;
6368 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6370 return FALSE;
6373 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6375 FIXME("(%p, %p): stub\n", font, glyphset);
6376 return 0;
6379 BOOL WineEngFontIsLinked(GdiFont *font)
6381 return FALSE;
6384 /*************************************************************************
6385 * GetRasterizerCaps (GDI32.@)
6387 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6389 lprs->nSize = sizeof(RASTERIZER_STATUS);
6390 lprs->wFlags = 0;
6391 lprs->nLanguageID = 0;
6392 return TRUE;
6395 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6397 ERR("called but we don't have FreeType\n");
6398 return 0;
6401 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6403 ERR("called but we don't have FreeType\n");
6404 return FALSE;
6407 #endif /* HAVE_FREETYPE */