push 8724397e7ede0f147b6e05994a72142d44d4fecc
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob99626d09393a22e52d9e15804b5e12aae76a3f03
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;
2089 GDI_CheckNotLock();
2091 if (ft_handle) /* do it only if we have freetype up and running */
2093 char *unixname;
2095 if(flags)
2096 FIXME("Ignoring flags %x\n", flags);
2098 if((unixname = wine_get_unix_file_name(file)))
2100 EnterCriticalSection( &freetype_cs );
2101 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2102 LeaveCriticalSection( &freetype_cs );
2103 HeapFree(GetProcessHeap(), 0, unixname);
2105 if (!ret && !strchrW(file, '\\')) {
2106 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2107 ret = load_font_from_winfonts_dir(file);
2108 if (!ret) {
2109 /* Try in datadir/fonts (or builddir/fonts),
2110 * needed for Magic the Gathering Online
2112 ret = load_font_from_data_dir(file);
2116 return ret;
2119 /*************************************************************
2120 * WineEngAddFontMemResourceEx
2123 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2125 GDI_CheckNotLock();
2127 if (ft_handle) /* do it only if we have freetype up and running */
2129 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2131 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2132 memcpy(pFontCopy, pbFont, cbFont);
2134 EnterCriticalSection( &freetype_cs );
2135 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2136 LeaveCriticalSection( &freetype_cs );
2138 if (*pcFonts == 0)
2140 TRACE("AddFontToList failed\n");
2141 HeapFree(GetProcessHeap(), 0, pFontCopy);
2142 return NULL;
2144 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2145 * For now return something unique but quite random
2147 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2148 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2151 *pcFonts = 0;
2152 return 0;
2155 /*************************************************************
2156 * WineEngRemoveFontResourceEx
2159 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2161 GDI_CheckNotLock();
2162 FIXME(":stub\n");
2163 return TRUE;
2166 static const struct nls_update_font_list
2168 UINT ansi_cp, oem_cp;
2169 const char *oem, *fixed, *system;
2170 const char *courier, *serif, *small, *sserif;
2171 /* these are for font substitutes */
2172 const char *shelldlg, *tmsrmn;
2173 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2174 *helv_0, *tmsrmn_0;
2175 const struct subst
2177 const char *from, *to;
2178 } arial_0, courier_new_0, times_new_roman_0;
2179 } nls_update_font_list[] =
2181 /* Latin 1 (United States) */
2182 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2183 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2184 "Tahoma","Times New Roman",
2185 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2186 { 0 }, { 0 }, { 0 }
2188 /* Latin 1 (Multilingual) */
2189 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2190 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2191 "Tahoma","Times New Roman", /* FIXME unverified */
2192 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2193 { 0 }, { 0 }, { 0 }
2195 /* Eastern Europe */
2196 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2197 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2198 "Tahoma","Times New Roman", /* FIXME unverified */
2199 "Fixedsys,238", "System,238",
2200 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2201 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2202 { "Arial CE,0", "Arial,238" },
2203 { "Courier New CE,0", "Courier New,238" },
2204 { "Times New Roman CE,0", "Times New Roman,238" }
2206 /* Cyrillic */
2207 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2208 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 "Fixedsys,204", "System,204",
2211 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2212 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2213 { "Arial Cyr,0", "Arial,204" },
2214 { "Courier New Cyr,0", "Courier New,204" },
2215 { "Times New Roman Cyr,0", "Times New Roman,204" }
2217 /* Greek */
2218 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2219 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2220 "Tahoma","Times New Roman", /* FIXME unverified */
2221 "Fixedsys,161", "System,161",
2222 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2223 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2224 { "Arial Greek,0", "Arial,161" },
2225 { "Courier New Greek,0", "Courier New,161" },
2226 { "Times New Roman Greek,0", "Times New Roman,161" }
2228 /* Turkish */
2229 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2230 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2231 "Tahoma","Times New Roman", /* FIXME unverified */
2232 "Fixedsys,162", "System,162",
2233 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2234 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2235 { "Arial Tur,0", "Arial,162" },
2236 { "Courier New Tur,0", "Courier New,162" },
2237 { "Times New Roman Tur,0", "Times New Roman,162" }
2239 /* Hebrew */
2240 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2241 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2242 "Tahoma","Times New Roman", /* FIXME unverified */
2243 "Fixedsys,177", "System,177",
2244 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2245 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2246 { 0 }, { 0 }, { 0 }
2248 /* Arabic */
2249 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2250 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2251 "Tahoma","Times New Roman", /* FIXME unverified */
2252 "Fixedsys,178", "System,178",
2253 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2254 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2255 { 0 }, { 0 }, { 0 }
2257 /* Baltic */
2258 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2259 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2260 "Tahoma","Times New Roman", /* FIXME unverified */
2261 "Fixedsys,186", "System,186",
2262 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2263 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2264 { "Arial Baltic,0", "Arial,186" },
2265 { "Courier New Baltic,0", "Courier New,186" },
2266 { "Times New Roman Baltic,0", "Times New Roman,186" }
2268 /* Vietnamese */
2269 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2270 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2271 "Tahoma","Times New Roman", /* FIXME unverified */
2272 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2273 { 0 }, { 0 }, { 0 }
2275 /* Thai */
2276 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2277 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2280 { 0 }, { 0 }, { 0 }
2282 /* Japanese */
2283 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2284 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2285 "MS UI Gothic","MS Serif",
2286 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2287 { 0 }, { 0 }, { 0 }
2289 /* Chinese Simplified */
2290 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2291 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2292 "SimSun", "NSimSun",
2293 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2294 { 0 }, { 0 }, { 0 }
2296 /* Korean */
2297 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2299 "Gulim", "Batang",
2300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2301 { 0 }, { 0 }, { 0 }
2303 /* Chinese Traditional */
2304 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2306 "PMingLiU", "MingLiU",
2307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2308 { 0 }, { 0 }, { 0 }
2312 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2314 return ( ansi_cp == 932 /* CP932 for Japanese */
2315 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2316 || ansi_cp == 949 /* CP949 for Korean */
2317 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2320 static inline HKEY create_fonts_NT_registry_key(void)
2322 HKEY hkey = 0;
2324 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2325 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2326 return hkey;
2329 static inline HKEY create_fonts_9x_registry_key(void)
2331 HKEY hkey = 0;
2333 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2334 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2335 return hkey;
2338 static inline HKEY create_config_fonts_registry_key(void)
2340 HKEY hkey = 0;
2342 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2343 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2344 return hkey;
2347 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2349 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2350 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2351 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2352 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2355 static void set_value_key(HKEY hkey, const char *name, const char *value)
2357 if (value)
2358 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2359 else if (name)
2360 RegDeleteValueA(hkey, name);
2363 static void update_font_info(void)
2365 char buf[40], cpbuf[40];
2366 DWORD len, type;
2367 HKEY hkey = 0;
2368 UINT i, ansi_cp = 0, oem_cp = 0;
2369 BOOL done = FALSE;
2371 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2372 return;
2374 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2375 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2376 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2377 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2378 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2380 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2381 if (is_dbcs_ansi_cp(ansi_cp))
2382 use_default_fallback = TRUE;
2384 len = sizeof(buf);
2385 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2387 if (!strcmp( buf, cpbuf )) /* already set correctly */
2389 RegCloseKey(hkey);
2390 return;
2392 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2394 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2396 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2397 RegCloseKey(hkey);
2399 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2401 HKEY hkey;
2403 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2404 nls_update_font_list[i].oem_cp == oem_cp)
2406 hkey = create_config_fonts_registry_key();
2407 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2408 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2409 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2410 RegCloseKey(hkey);
2412 hkey = create_fonts_NT_registry_key();
2413 add_font_list(hkey, &nls_update_font_list[i]);
2414 RegCloseKey(hkey);
2416 hkey = create_fonts_9x_registry_key();
2417 add_font_list(hkey, &nls_update_font_list[i]);
2418 RegCloseKey(hkey);
2420 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2422 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2423 strlen(nls_update_font_list[i].shelldlg)+1);
2424 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2425 strlen(nls_update_font_list[i].tmsrmn)+1);
2427 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2428 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2429 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2430 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2431 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2432 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2433 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2434 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2436 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2437 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2438 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2440 RegCloseKey(hkey);
2442 done = TRUE;
2444 else
2446 /* Delete the FontSubstitutes from other locales */
2447 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2449 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2450 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2451 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2452 RegCloseKey(hkey);
2456 if (!done)
2457 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2461 static BOOL init_freetype(void)
2463 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2464 if(!ft_handle) {
2465 WINE_MESSAGE(
2466 "Wine cannot find the FreeType font library. To enable Wine to\n"
2467 "use TrueType fonts please install a version of FreeType greater than\n"
2468 "or equal to 2.0.5.\n"
2469 "http://www.freetype.org\n");
2470 return FALSE;
2473 #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;}
2475 LOAD_FUNCPTR(FT_Vector_Unit)
2476 LOAD_FUNCPTR(FT_Done_Face)
2477 LOAD_FUNCPTR(FT_Get_Char_Index)
2478 LOAD_FUNCPTR(FT_Get_Module)
2479 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2480 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2481 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2482 LOAD_FUNCPTR(FT_Init_FreeType)
2483 LOAD_FUNCPTR(FT_Load_Glyph)
2484 LOAD_FUNCPTR(FT_Matrix_Multiply)
2485 #ifndef FT_MULFIX_INLINED
2486 LOAD_FUNCPTR(FT_MulFix)
2487 #endif
2488 LOAD_FUNCPTR(FT_New_Face)
2489 LOAD_FUNCPTR(FT_New_Memory_Face)
2490 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2491 LOAD_FUNCPTR(FT_Outline_Transform)
2492 LOAD_FUNCPTR(FT_Outline_Translate)
2493 LOAD_FUNCPTR(FT_Select_Charmap)
2494 LOAD_FUNCPTR(FT_Set_Charmap)
2495 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2496 LOAD_FUNCPTR(FT_Vector_Transform)
2497 LOAD_FUNCPTR(FT_Render_Glyph)
2499 #undef LOAD_FUNCPTR
2500 /* Don't warn if these ones are missing */
2501 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2502 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2503 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2504 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2505 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2506 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2507 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2508 #endif
2509 #ifdef HAVE_FREETYPE_FTWINFNT_H
2510 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2511 #endif
2512 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2513 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2514 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2515 <= 2.0.3 has FT_Sqrt64 */
2516 goto sym_not_found;
2519 if(pFT_Init_FreeType(&library) != 0) {
2520 ERR("Can't init FreeType library\n");
2521 wine_dlclose(ft_handle, NULL, 0);
2522 ft_handle = NULL;
2523 return FALSE;
2525 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2526 if (pFT_Library_Version)
2527 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2529 if (FT_Version.major<=0)
2531 FT_Version.major=2;
2532 FT_Version.minor=0;
2533 FT_Version.patch=5;
2535 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2536 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2537 ((FT_Version.minor << 8) & 0x00ff00) |
2538 ((FT_Version.patch ) & 0x0000ff);
2540 return TRUE;
2542 sym_not_found:
2543 WINE_MESSAGE(
2544 "Wine cannot find certain functions that it needs inside the FreeType\n"
2545 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2546 "FreeType to at least version 2.0.5.\n"
2547 "http://www.freetype.org\n");
2548 wine_dlclose(ft_handle, NULL, 0);
2549 ft_handle = NULL;
2550 return FALSE;
2553 /*************************************************************
2554 * WineEngInit
2556 * Initialize FreeType library and create a list of available faces
2558 BOOL WineEngInit(void)
2560 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2561 static const WCHAR pathW[] = {'P','a','t','h',0};
2562 HKEY hkey;
2563 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2564 WCHAR windowsdir[MAX_PATH];
2565 char *unixname;
2566 HANDLE font_mutex;
2567 const char *data_dir;
2569 TRACE("\n");
2571 /* update locale dependent font info in registry */
2572 update_font_info();
2574 if(!init_freetype()) return FALSE;
2576 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2577 ERR("Failed to create font mutex\n");
2578 return FALSE;
2580 WaitForSingleObject(font_mutex, INFINITE);
2582 delete_external_font_keys();
2584 /* load the system bitmap fonts */
2585 load_system_fonts();
2587 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2588 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2589 strcatW(windowsdir, fontsW);
2590 if((unixname = wine_get_unix_file_name(windowsdir)))
2592 ReadFontDir(unixname, FALSE);
2593 HeapFree(GetProcessHeap(), 0, unixname);
2596 /* load the system truetype fonts */
2597 data_dir = wine_get_data_dir();
2598 if (!data_dir) data_dir = wine_get_build_dir();
2599 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2600 strcpy(unixname, data_dir);
2601 strcat(unixname, "/fonts/");
2602 ReadFontDir(unixname, TRUE);
2603 HeapFree(GetProcessHeap(), 0, unixname);
2606 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2607 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2608 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2609 will skip these. */
2610 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2611 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2612 &hkey) == ERROR_SUCCESS) {
2613 LPWSTR data, valueW;
2614 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2615 &valuelen, &datalen, NULL, NULL);
2617 valuelen++; /* returned value doesn't include room for '\0' */
2618 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2619 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2620 if (valueW && data)
2622 dlen = datalen * sizeof(WCHAR);
2623 vlen = valuelen;
2624 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2625 &dlen) == ERROR_SUCCESS) {
2626 if(data[0] && (data[1] == ':'))
2628 if((unixname = wine_get_unix_file_name(data)))
2630 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2631 HeapFree(GetProcessHeap(), 0, unixname);
2634 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2636 WCHAR pathW[MAX_PATH];
2637 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2638 BOOL added = FALSE;
2640 sprintfW(pathW, fmtW, windowsdir, data);
2641 if((unixname = wine_get_unix_file_name(pathW)))
2643 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2644 HeapFree(GetProcessHeap(), 0, unixname);
2646 if (!added)
2647 load_font_from_data_dir(data);
2649 /* reset dlen and vlen */
2650 dlen = datalen;
2651 vlen = valuelen;
2654 HeapFree(GetProcessHeap(), 0, data);
2655 HeapFree(GetProcessHeap(), 0, valueW);
2656 RegCloseKey(hkey);
2659 load_fontconfig_fonts();
2661 /* then look in any directories that we've specified in the config file */
2662 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2663 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2665 DWORD len;
2666 LPWSTR valueW;
2667 LPSTR valueA, ptr;
2669 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2671 len += sizeof(WCHAR);
2672 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2673 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2675 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2676 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2677 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2678 TRACE( "got font path %s\n", debugstr_a(valueA) );
2679 ptr = valueA;
2680 while (ptr)
2682 LPSTR next = strchr( ptr, ':' );
2683 if (next) *next++ = 0;
2684 ReadFontDir( ptr, TRUE );
2685 ptr = next;
2687 HeapFree( GetProcessHeap(), 0, valueA );
2689 HeapFree( GetProcessHeap(), 0, valueW );
2691 RegCloseKey(hkey);
2694 DumpFontList();
2695 LoadSubstList();
2696 DumpSubstList();
2697 LoadReplaceList();
2698 update_reg_entries();
2700 init_system_links();
2702 ReleaseMutex(font_mutex);
2703 return TRUE;
2707 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2709 TT_OS2 *pOS2;
2710 TT_HoriHeader *pHori;
2712 LONG ppem;
2714 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2715 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2717 if(height == 0) height = 16;
2719 /* Calc. height of EM square:
2721 * For +ve lfHeight we have
2722 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2723 * Re-arranging gives:
2724 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2726 * For -ve lfHeight we have
2727 * |lfHeight| = ppem
2728 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2729 * with il = winAscent + winDescent - units_per_em]
2733 if(height > 0) {
2734 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2735 ppem = MulDiv(ft_face->units_per_EM, height,
2736 pHori->Ascender - pHori->Descender);
2737 else
2738 ppem = MulDiv(ft_face->units_per_EM, height,
2739 pOS2->usWinAscent + pOS2->usWinDescent);
2741 else
2742 ppem = -height;
2744 return ppem;
2747 static struct font_mapping *map_font_file( const char *name )
2749 struct font_mapping *mapping;
2750 struct stat st;
2751 int fd;
2753 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2754 if (fstat( fd, &st ) == -1) goto error;
2756 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2758 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2760 mapping->refcount++;
2761 close( fd );
2762 return mapping;
2765 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2766 goto error;
2768 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2769 close( fd );
2771 if (mapping->data == MAP_FAILED)
2773 HeapFree( GetProcessHeap(), 0, mapping );
2774 return NULL;
2776 mapping->refcount = 1;
2777 mapping->dev = st.st_dev;
2778 mapping->ino = st.st_ino;
2779 mapping->size = st.st_size;
2780 list_add_tail( &mappings_list, &mapping->entry );
2781 return mapping;
2783 error:
2784 close( fd );
2785 return NULL;
2788 static void unmap_font_file( struct font_mapping *mapping )
2790 if (!--mapping->refcount)
2792 list_remove( &mapping->entry );
2793 munmap( mapping->data, mapping->size );
2794 HeapFree( GetProcessHeap(), 0, mapping );
2798 static LONG load_VDMX(GdiFont*, LONG);
2800 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2802 FT_Error err;
2803 FT_Face ft_face;
2804 void *data_ptr;
2805 DWORD data_size;
2807 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2809 if (face->file)
2811 if (!(font->mapping = map_font_file( face->file )))
2813 WARN("failed to map %s\n", debugstr_a(face->file));
2814 return 0;
2816 data_ptr = font->mapping->data;
2817 data_size = font->mapping->size;
2819 else
2821 data_ptr = face->font_data_ptr;
2822 data_size = face->font_data_size;
2825 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2826 if(err) {
2827 ERR("FT_New_Face rets %d\n", err);
2828 return 0;
2831 /* set it here, as load_VDMX needs it */
2832 font->ft_face = ft_face;
2834 if(FT_IS_SCALABLE(ft_face)) {
2835 /* load the VDMX table if we have one */
2836 font->ppem = load_VDMX(font, height);
2837 if(font->ppem == 0)
2838 font->ppem = calc_ppem_for_height(ft_face, height);
2839 TRACE("height %d => ppem %d\n", height, font->ppem);
2841 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2842 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2843 } else {
2844 font->ppem = height;
2845 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2846 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2848 return ft_face;
2852 static int get_nearest_charset(Face *face, int *cp)
2854 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2855 a single face with the requested charset. The idea is to check if
2856 the selected font supports the current ANSI codepage, if it does
2857 return the corresponding charset, else return the first charset */
2859 CHARSETINFO csi;
2860 int acp = GetACP(), i;
2861 DWORD fs0;
2863 *cp = acp;
2864 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2865 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2866 return csi.ciCharset;
2868 for(i = 0; i < 32; i++) {
2869 fs0 = 1L << i;
2870 if(face->fs.fsCsb[0] & fs0) {
2871 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2872 *cp = csi.ciACP;
2873 return csi.ciCharset;
2875 else
2876 FIXME("TCI failing on %x\n", fs0);
2880 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2881 face->fs.fsCsb[0], face->file);
2882 *cp = acp;
2883 return DEFAULT_CHARSET;
2886 static GdiFont *alloc_font(void)
2888 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2889 ret->gmsize = 1;
2890 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2891 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2892 ret->potm = NULL;
2893 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2894 ret->total_kern_pairs = (DWORD)-1;
2895 ret->kern_pairs = NULL;
2896 list_init(&ret->hfontlist);
2897 list_init(&ret->child_fonts);
2898 return ret;
2901 static void free_font(GdiFont *font)
2903 struct list *cursor, *cursor2;
2904 DWORD i;
2906 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2908 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2909 struct list *first_hfont;
2910 HFONTLIST *hfontlist;
2911 list_remove(cursor);
2912 if(child->font)
2914 first_hfont = list_head(&child->font->hfontlist);
2915 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2916 DeleteObject(hfontlist->hfont);
2917 HeapFree(GetProcessHeap(), 0, hfontlist);
2918 free_font(child->font);
2920 HeapFree(GetProcessHeap(), 0, child);
2923 if (font->ft_face) pFT_Done_Face(font->ft_face);
2924 if (font->mapping) unmap_font_file( font->mapping );
2925 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2926 HeapFree(GetProcessHeap(), 0, font->potm);
2927 HeapFree(GetProcessHeap(), 0, font->name);
2928 for (i = 0; i < font->gmsize; i++)
2929 HeapFree(GetProcessHeap(),0,font->gm[i]);
2930 HeapFree(GetProcessHeap(), 0, font->gm);
2931 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2932 HeapFree(GetProcessHeap(), 0, font);
2936 /*************************************************************
2937 * load_VDMX
2939 * load the vdmx entry for the specified height
2942 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2943 ( ( (FT_ULong)_x4 << 24 ) | \
2944 ( (FT_ULong)_x3 << 16 ) | \
2945 ( (FT_ULong)_x2 << 8 ) | \
2946 (FT_ULong)_x1 )
2948 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2950 typedef struct {
2951 BYTE bCharSet;
2952 BYTE xRatio;
2953 BYTE yStartRatio;
2954 BYTE yEndRatio;
2955 } Ratios;
2957 typedef struct {
2958 WORD recs;
2959 BYTE startsz;
2960 BYTE endsz;
2961 } VDMX_group;
2963 static LONG load_VDMX(GdiFont *font, LONG height)
2965 WORD hdr[3], tmp;
2966 VDMX_group group;
2967 BYTE devXRatio, devYRatio;
2968 USHORT numRecs, numRatios;
2969 DWORD result, offset = -1;
2970 LONG ppem = 0;
2971 int i;
2973 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2975 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2976 return ppem;
2978 /* FIXME: need the real device aspect ratio */
2979 devXRatio = 1;
2980 devYRatio = 1;
2982 numRecs = GET_BE_WORD(hdr[1]);
2983 numRatios = GET_BE_WORD(hdr[2]);
2985 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2986 for(i = 0; i < numRatios; i++) {
2987 Ratios ratio;
2989 offset = (3 * 2) + (i * sizeof(Ratios));
2990 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2991 offset = -1;
2993 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2995 if((ratio.xRatio == 0 &&
2996 ratio.yStartRatio == 0 &&
2997 ratio.yEndRatio == 0) ||
2998 (devXRatio == ratio.xRatio &&
2999 devYRatio >= ratio.yStartRatio &&
3000 devYRatio <= ratio.yEndRatio))
3002 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3003 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3004 offset = GET_BE_WORD(tmp);
3005 break;
3009 if(offset == -1) {
3010 FIXME("No suitable ratio found\n");
3011 return ppem;
3014 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3015 USHORT recs;
3016 BYTE startsz, endsz;
3017 WORD *vTable;
3019 recs = GET_BE_WORD(group.recs);
3020 startsz = group.startsz;
3021 endsz = group.endsz;
3023 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3025 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3026 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3027 if(result == GDI_ERROR) {
3028 FIXME("Failed to retrieve vTable\n");
3029 goto end;
3032 if(height > 0) {
3033 for(i = 0; i < recs; i++) {
3034 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3035 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3036 ppem = GET_BE_WORD(vTable[i * 3]);
3038 if(yMax + -yMin == height) {
3039 font->yMax = yMax;
3040 font->yMin = yMin;
3041 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3042 break;
3044 if(yMax + -yMin > height) {
3045 if(--i < 0) {
3046 ppem = 0;
3047 goto end; /* failed */
3049 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3050 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3051 ppem = GET_BE_WORD(vTable[i * 3]);
3052 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3053 break;
3056 if(!font->yMax) {
3057 ppem = 0;
3058 TRACE("ppem not found for height %d\n", height);
3060 } else {
3061 ppem = -height;
3062 if(ppem < startsz || ppem > endsz)
3063 goto end;
3065 for(i = 0; i < recs; i++) {
3066 USHORT yPelHeight;
3067 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3069 if(yPelHeight > ppem)
3070 break; /* failed */
3072 if(yPelHeight == ppem) {
3073 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3074 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3075 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3076 break;
3080 end:
3081 HeapFree(GetProcessHeap(), 0, vTable);
3084 return ppem;
3087 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3089 if(font->font_desc.hash != fd->hash) return TRUE;
3090 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3091 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3092 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3093 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3096 static void calc_hash(FONT_DESC *pfd)
3098 DWORD hash = 0, *ptr, two_chars;
3099 WORD *pwc;
3100 unsigned int i;
3102 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3103 hash ^= *ptr;
3104 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3105 hash ^= *ptr;
3106 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3107 two_chars = *ptr;
3108 pwc = (WCHAR *)&two_chars;
3109 if(!*pwc) break;
3110 *pwc = toupperW(*pwc);
3111 pwc++;
3112 *pwc = toupperW(*pwc);
3113 hash ^= two_chars;
3114 if(!*pwc) break;
3116 hash ^= !pfd->can_use_bitmap;
3117 pfd->hash = hash;
3118 return;
3121 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3123 GdiFont *ret;
3124 FONT_DESC fd;
3125 HFONTLIST *hflist;
3126 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3128 fd.lf = *plf;
3129 fd.matrix = *pmat;
3130 fd.can_use_bitmap = can_use_bitmap;
3131 calc_hash(&fd);
3133 /* try the child list */
3134 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3135 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3136 if(!fontcmp(ret, &fd)) {
3137 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3138 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3139 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3140 if(hflist->hfont == hfont)
3141 return ret;
3146 /* try the in-use list */
3147 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3148 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3149 if(!fontcmp(ret, &fd)) {
3150 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3151 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3152 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3153 if(hflist->hfont == hfont)
3154 return ret;
3156 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3157 hflist->hfont = hfont;
3158 list_add_head(&ret->hfontlist, &hflist->entry);
3159 return ret;
3163 /* then the unused list */
3164 font_elem_ptr = list_head(&unused_gdi_font_list);
3165 while(font_elem_ptr) {
3166 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3167 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3168 if(!fontcmp(ret, &fd)) {
3169 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3170 assert(list_empty(&ret->hfontlist));
3171 TRACE("Found %p in unused list\n", ret);
3172 list_remove(&ret->entry);
3173 list_add_head(&gdi_font_list, &ret->entry);
3174 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3175 hflist->hfont = hfont;
3176 list_add_head(&ret->hfontlist, &hflist->entry);
3177 return ret;
3180 return NULL;
3183 static void add_to_cache(GdiFont *font)
3185 static DWORD cache_num = 1;
3187 font->cache_num = cache_num++;
3188 list_add_head(&gdi_font_list, &font->entry);
3191 /*************************************************************
3192 * create_child_font_list
3194 static BOOL create_child_font_list(GdiFont *font)
3196 BOOL ret = FALSE;
3197 SYSTEM_LINKS *font_link;
3198 CHILD_FONT *font_link_entry, *new_child;
3200 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3202 if(!strcmpW(font_link->font_name, font->name))
3204 TRACE("found entry in system list\n");
3205 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3207 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3208 new_child->face = font_link_entry->face;
3209 new_child->font = NULL;
3210 list_add_tail(&font->child_fonts, &new_child->entry);
3211 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3213 ret = TRUE;
3214 break;
3218 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3219 * Sans Serif. This is how asian windows get default fallbacks for fonts
3221 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3222 font->charset != OEM_CHARSET &&
3223 strcmpW(font->name,szDefaultFallbackLink) != 0)
3224 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3226 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3228 TRACE("found entry in default fallback list\n");
3229 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3231 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3232 new_child->face = font_link_entry->face;
3233 new_child->font = NULL;
3234 list_add_tail(&font->child_fonts, &new_child->entry);
3235 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3237 ret = TRUE;
3238 break;
3242 return ret;
3245 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3247 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3249 if (pFT_Set_Charmap)
3251 FT_Int i;
3252 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3254 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3256 for (i = 0; i < ft_face->num_charmaps; i++)
3258 if (ft_face->charmaps[i]->encoding == encoding)
3260 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3261 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3263 switch (ft_face->charmaps[i]->platform_id)
3265 default:
3266 cmap_def = ft_face->charmaps[i];
3267 break;
3268 case 0: /* Apple Unicode */
3269 cmap0 = ft_face->charmaps[i];
3270 break;
3271 case 1: /* Macintosh */
3272 cmap1 = ft_face->charmaps[i];
3273 break;
3274 case 2: /* ISO */
3275 cmap2 = ft_face->charmaps[i];
3276 break;
3277 case 3: /* Microsoft */
3278 cmap3 = ft_face->charmaps[i];
3279 break;
3283 if (cmap3) /* prefer Microsoft cmap table */
3284 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3285 else if (cmap1)
3286 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3287 else if (cmap2)
3288 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3289 else if (cmap0)
3290 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3291 else if (cmap_def)
3292 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3294 return ft_err == FT_Err_Ok;
3297 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3300 /*************************************************************
3301 * WineEngCreateFontInstance
3304 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3306 GdiFont *ret;
3307 Face *face, *best, *best_bitmap;
3308 Family *family, *last_resort_family;
3309 struct list *family_elem_ptr, *face_elem_ptr;
3310 INT height, width = 0;
3311 unsigned int score = 0, new_score;
3312 signed int diff = 0, newdiff;
3313 BOOL bd, it, can_use_bitmap;
3314 LOGFONTW lf;
3315 CHARSETINFO csi;
3316 HFONTLIST *hflist;
3317 FMAT2 dcmat;
3318 FontSubst *psub = NULL;
3320 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3321 lf.lfWidth = abs(lf.lfWidth);
3323 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3325 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3326 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3327 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3328 lf.lfEscapement);
3330 if(dc->GraphicsMode == GM_ADVANCED)
3331 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3332 else
3334 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3335 font scaling abilities. */
3336 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3337 dcmat.eM21 = dcmat.eM12 = 0;
3340 /* Try to avoid not necessary glyph transformations */
3341 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3343 lf.lfHeight *= fabs(dcmat.eM11);
3344 lf.lfWidth *= fabs(dcmat.eM11);
3345 dcmat.eM11 = dcmat.eM22 = 1.0;
3348 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3349 dcmat.eM21, dcmat.eM22);
3351 GDI_CheckNotLock();
3352 EnterCriticalSection( &freetype_cs );
3354 /* check the cache first */
3355 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3356 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3357 LeaveCriticalSection( &freetype_cs );
3358 return ret;
3361 TRACE("not in cache\n");
3362 if(list_empty(&font_list)) /* No fonts installed */
3364 TRACE("No fonts installed\n");
3365 LeaveCriticalSection( &freetype_cs );
3366 return NULL;
3368 if(!have_installed_roman_font)
3370 TRACE("No roman font installed\n");
3371 LeaveCriticalSection( &freetype_cs );
3372 return NULL;
3375 ret = alloc_font();
3377 ret->font_desc.matrix = dcmat;
3378 ret->font_desc.lf = lf;
3379 ret->font_desc.can_use_bitmap = can_use_bitmap;
3380 calc_hash(&ret->font_desc);
3381 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3382 hflist->hfont = hfont;
3383 list_add_head(&ret->hfontlist, &hflist->entry);
3385 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3386 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3387 original value lfCharSet. Note this is a special case for
3388 Symbol and doesn't happen at least for "Wingdings*" */
3390 if(!strcmpiW(lf.lfFaceName, SymbolW))
3391 lf.lfCharSet = SYMBOL_CHARSET;
3393 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3394 switch(lf.lfCharSet) {
3395 case DEFAULT_CHARSET:
3396 csi.fs.fsCsb[0] = 0;
3397 break;
3398 default:
3399 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3400 csi.fs.fsCsb[0] = 0;
3401 break;
3405 family = NULL;
3406 if(lf.lfFaceName[0] != '\0') {
3407 SYSTEM_LINKS *font_link;
3408 CHILD_FONT *font_link_entry;
3409 LPWSTR FaceName = lf.lfFaceName;
3412 * Check for a leading '@' this signals that the font is being
3413 * requested in tategaki mode (vertical writing substitution) but
3414 * does not affect the fontface that is to be selected.
3416 if (lf.lfFaceName[0]=='@')
3417 FaceName = &lf.lfFaceName[1];
3419 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3421 if(psub) {
3422 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3423 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3424 if (psub->to.charset != -1)
3425 lf.lfCharSet = psub->to.charset;
3428 /* We want a match on name and charset or just name if
3429 charset was DEFAULT_CHARSET. If the latter then
3430 we fixup the returned charset later in get_nearest_charset
3431 where we'll either use the charset of the current ansi codepage
3432 or if that's unavailable the first charset that the font supports.
3434 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3435 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3436 if (!strcmpiW(family->FamilyName, FaceName) ||
3437 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3439 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3440 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3441 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3442 if(face->scalable || can_use_bitmap)
3443 goto found;
3449 * Try check the SystemLink list first for a replacement font.
3450 * We may find good replacements there.
3452 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3454 if(!strcmpiW(font_link->font_name, FaceName) ||
3455 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3457 TRACE("found entry in system list\n");
3458 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3460 face = font_link_entry->face;
3461 family = face->family;
3462 if(csi.fs.fsCsb[0] &
3463 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3465 if(face->scalable || can_use_bitmap)
3466 goto found;
3473 psub = NULL; /* substitution is no more relevant */
3475 /* If requested charset was DEFAULT_CHARSET then try using charset
3476 corresponding to the current ansi codepage */
3477 if (!csi.fs.fsCsb[0])
3479 INT acp = GetACP();
3480 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3481 FIXME("TCI failed on codepage %d\n", acp);
3482 csi.fs.fsCsb[0] = 0;
3483 } else
3484 lf.lfCharSet = csi.ciCharset;
3487 /* Face families are in the top 4 bits of lfPitchAndFamily,
3488 so mask with 0xF0 before testing */
3490 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3491 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3492 strcpyW(lf.lfFaceName, defFixed);
3493 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3494 strcpyW(lf.lfFaceName, defSerif);
3495 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3496 strcpyW(lf.lfFaceName, defSans);
3497 else
3498 strcpyW(lf.lfFaceName, defSans);
3499 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3500 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3501 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3502 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3503 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3504 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3505 if(face->scalable || can_use_bitmap)
3506 goto found;
3511 last_resort_family = NULL;
3512 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3513 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3514 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3515 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3516 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3517 if(face->scalable)
3518 goto found;
3519 if(can_use_bitmap && !last_resort_family)
3520 last_resort_family = family;
3525 if(last_resort_family) {
3526 family = last_resort_family;
3527 csi.fs.fsCsb[0] = 0;
3528 goto found;
3531 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3532 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3533 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3534 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3535 if(face->scalable) {
3536 csi.fs.fsCsb[0] = 0;
3537 WARN("just using first face for now\n");
3538 goto found;
3540 if(can_use_bitmap && !last_resort_family)
3541 last_resort_family = family;
3544 if(!last_resort_family) {
3545 FIXME("can't find a single appropriate font - bailing\n");
3546 free_font(ret);
3547 LeaveCriticalSection( &freetype_cs );
3548 return NULL;
3551 WARN("could only find a bitmap font - this will probably look awful!\n");
3552 family = last_resort_family;
3553 csi.fs.fsCsb[0] = 0;
3555 found:
3556 it = lf.lfItalic ? 1 : 0;
3557 bd = lf.lfWeight > 550 ? 1 : 0;
3559 height = lf.lfHeight;
3561 face = best = best_bitmap = NULL;
3562 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3564 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3566 BOOL italic, bold;
3568 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3569 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3570 new_score = (italic ^ it) + (bold ^ bd);
3571 if(!best || new_score <= score)
3573 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3574 italic, bold, it, bd);
3575 score = new_score;
3576 best = face;
3577 if(best->scalable && score == 0) break;
3578 if(!best->scalable)
3580 if(height > 0)
3581 newdiff = height - (signed int)(best->size.height);
3582 else
3583 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3584 if(!best_bitmap || new_score < score ||
3585 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3587 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3588 diff = newdiff;
3589 best_bitmap = best;
3590 if(score == 0 && diff == 0) break;
3596 if(best)
3597 face = best->scalable ? best : best_bitmap;
3598 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3599 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3601 ret->fs = face->fs;
3603 if(csi.fs.fsCsb[0]) {
3604 ret->charset = lf.lfCharSet;
3605 ret->codepage = csi.ciACP;
3607 else
3608 ret->charset = get_nearest_charset(face, &ret->codepage);
3610 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3611 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3613 ret->aveWidth = height ? lf.lfWidth : 0;
3615 if(!face->scalable) {
3616 /* Windows uses integer scaling factors for bitmap fonts */
3617 INT scale, scaled_height;
3619 /* FIXME: rotation of bitmap fonts is ignored */
3620 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3621 if (ret->aveWidth)
3622 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3623 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3625 if (height != 0) height = diff;
3626 height += face->size.height;
3628 scale = (height + face->size.height - 1) / face->size.height;
3629 scaled_height = scale * face->size.height;
3630 /* Only jump to the next height if the difference <= 25% original height */
3631 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3632 /* The jump between unscaled and doubled is delayed by 1 */
3633 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3634 ret->scale_y = scale;
3636 width = face->size.x_ppem >> 6;
3637 height = face->size.y_ppem >> 6;
3639 else
3640 ret->scale_y = 1.0;
3641 TRACE("font scale y: %f\n", ret->scale_y);
3643 ret->ft_face = OpenFontFace(ret, face, width, height);
3645 if (!ret->ft_face)
3647 free_font( ret );
3648 LeaveCriticalSection( &freetype_cs );
3649 return 0;
3652 ret->ntmFlags = face->ntmFlags;
3654 if (ret->charset == SYMBOL_CHARSET &&
3655 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3656 /* No ops */
3658 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3659 /* No ops */
3661 else {
3662 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3665 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3666 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3667 ret->underline = lf.lfUnderline ? 0xff : 0;
3668 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3669 create_child_font_list(ret);
3671 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3673 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3674 if (length != GDI_ERROR)
3676 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3677 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3678 TRACE("Loaded GSUB table of %i bytes\n",length);
3682 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3684 add_to_cache(ret);
3685 LeaveCriticalSection( &freetype_cs );
3686 return ret;
3689 static void dump_gdi_font_list(void)
3691 GdiFont *gdiFont;
3692 struct list *elem_ptr;
3694 TRACE("---------- gdiFont Cache ----------\n");
3695 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3696 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3697 TRACE("gdiFont=%p %s %d\n",
3698 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3701 TRACE("---------- Unused gdiFont Cache ----------\n");
3702 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3703 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3704 TRACE("gdiFont=%p %s %d\n",
3705 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3709 /*************************************************************
3710 * WineEngDestroyFontInstance
3712 * free the gdiFont associated with this handle
3715 BOOL WineEngDestroyFontInstance(HFONT handle)
3717 GdiFont *gdiFont;
3718 HFONTLIST *hflist;
3719 BOOL ret = FALSE;
3720 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3721 int i = 0;
3723 GDI_CheckNotLock();
3724 EnterCriticalSection( &freetype_cs );
3726 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3728 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3729 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3730 if(hflist->hfont == handle)
3732 TRACE("removing child font %p from child list\n", gdiFont);
3733 list_remove(&gdiFont->entry);
3734 LeaveCriticalSection( &freetype_cs );
3735 return TRUE;
3739 TRACE("destroying hfont=%p\n", handle);
3740 if(TRACE_ON(font))
3741 dump_gdi_font_list();
3743 font_elem_ptr = list_head(&gdi_font_list);
3744 while(font_elem_ptr) {
3745 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3746 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3748 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3749 while(hfontlist_elem_ptr) {
3750 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3751 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3752 if(hflist->hfont == handle) {
3753 list_remove(&hflist->entry);
3754 HeapFree(GetProcessHeap(), 0, hflist);
3755 ret = TRUE;
3758 if(list_empty(&gdiFont->hfontlist)) {
3759 TRACE("Moving to Unused list\n");
3760 list_remove(&gdiFont->entry);
3761 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3766 font_elem_ptr = list_head(&unused_gdi_font_list);
3767 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3768 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3769 while(font_elem_ptr) {
3770 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3771 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3772 TRACE("freeing %p\n", gdiFont);
3773 list_remove(&gdiFont->entry);
3774 free_font(gdiFont);
3776 LeaveCriticalSection( &freetype_cs );
3777 return ret;
3780 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3781 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3783 GdiFont *font;
3784 LONG width, height;
3786 if (face->cached_enum_data)
3788 TRACE("Cached\n");
3789 *pelf = face->cached_enum_data->elf;
3790 *pntm = face->cached_enum_data->ntm;
3791 *ptype = face->cached_enum_data->type;
3792 return;
3795 font = alloc_font();
3797 if(face->scalable) {
3798 height = -2048; /* 2048 is the most common em size */
3799 width = 0;
3800 } else {
3801 height = face->size.y_ppem >> 6;
3802 width = face->size.x_ppem >> 6;
3804 font->scale_y = 1.0;
3806 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3808 free_font(font);
3809 return;
3812 font->name = strdupW(face->family->FamilyName);
3813 font->ntmFlags = face->ntmFlags;
3815 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3817 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3819 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3821 lstrcpynW(pelf->elfLogFont.lfFaceName,
3822 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3823 LF_FACESIZE);
3824 lstrcpynW(pelf->elfFullName,
3825 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3826 LF_FULLFACESIZE);
3827 lstrcpynW(pelf->elfStyle,
3828 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3829 LF_FACESIZE);
3831 else
3833 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3835 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3837 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3838 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3839 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3842 pntm->ntmTm.ntmFlags = face->ntmFlags;
3843 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3844 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3845 pntm->ntmFontSig = face->fs;
3847 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3849 pelf->elfLogFont.lfEscapement = 0;
3850 pelf->elfLogFont.lfOrientation = 0;
3851 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3852 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3853 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3854 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3855 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3856 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3857 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3858 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3859 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3860 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3861 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3863 *ptype = 0;
3864 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3865 *ptype |= TRUETYPE_FONTTYPE;
3866 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3867 *ptype |= DEVICE_FONTTYPE;
3868 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3869 *ptype |= RASTER_FONTTYPE;
3871 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3872 if (face->cached_enum_data)
3874 face->cached_enum_data->elf = *pelf;
3875 face->cached_enum_data->ntm = *pntm;
3876 face->cached_enum_data->type = *ptype;
3879 free_font(font);
3882 /*************************************************************
3883 * WineEngEnumFonts
3886 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3888 Family *family;
3889 Face *face;
3890 struct list *family_elem_ptr, *face_elem_ptr;
3891 ENUMLOGFONTEXW elf;
3892 NEWTEXTMETRICEXW ntm;
3893 DWORD type;
3894 FONTSIGNATURE fs;
3895 CHARSETINFO csi;
3896 LOGFONTW lf;
3897 int i;
3899 if (!plf)
3901 lf.lfCharSet = DEFAULT_CHARSET;
3902 lf.lfPitchAndFamily = 0;
3903 lf.lfFaceName[0] = 0;
3904 plf = &lf;
3907 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3909 GDI_CheckNotLock();
3910 EnterCriticalSection( &freetype_cs );
3911 if(plf->lfFaceName[0]) {
3912 FontSubst *psub;
3913 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3915 if(psub) {
3916 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3917 debugstr_w(psub->to.name));
3918 lf = *plf;
3919 strcpyW(lf.lfFaceName, psub->to.name);
3920 plf = &lf;
3923 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3924 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3925 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3926 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3927 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3928 GetEnumStructs(face, &elf, &ntm, &type);
3929 for(i = 0; i < 32; i++) {
3930 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3931 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3932 strcpyW(elf.elfScript, OEM_DOSW);
3933 i = 32; /* break out of loop */
3934 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3935 continue;
3936 else {
3937 fs.fsCsb[0] = 1L << i;
3938 fs.fsCsb[1] = 0;
3939 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3940 TCI_SRCFONTSIG))
3941 csi.ciCharset = DEFAULT_CHARSET;
3942 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3943 if(csi.ciCharset != DEFAULT_CHARSET) {
3944 elf.elfLogFont.lfCharSet =
3945 ntm.ntmTm.tmCharSet = csi.ciCharset;
3946 if(ElfScriptsW[i])
3947 strcpyW(elf.elfScript, ElfScriptsW[i]);
3948 else
3949 FIXME("Unknown elfscript for bit %d\n", i);
3952 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3953 debugstr_w(elf.elfLogFont.lfFaceName),
3954 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3955 csi.ciCharset, type, debugstr_w(elf.elfScript),
3956 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3957 ntm.ntmTm.ntmFlags);
3958 /* release section before callback (FIXME) */
3959 LeaveCriticalSection( &freetype_cs );
3960 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3961 EnterCriticalSection( &freetype_cs );
3966 } else {
3967 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3968 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3969 face_elem_ptr = list_head(&family->faces);
3970 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3971 GetEnumStructs(face, &elf, &ntm, &type);
3972 for(i = 0; i < 32; i++) {
3973 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3974 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3975 strcpyW(elf.elfScript, OEM_DOSW);
3976 i = 32; /* break out of loop */
3977 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3978 continue;
3979 else {
3980 fs.fsCsb[0] = 1L << i;
3981 fs.fsCsb[1] = 0;
3982 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3983 TCI_SRCFONTSIG))
3984 csi.ciCharset = DEFAULT_CHARSET;
3985 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3986 if(csi.ciCharset != DEFAULT_CHARSET) {
3987 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3988 csi.ciCharset;
3989 if(ElfScriptsW[i])
3990 strcpyW(elf.elfScript, ElfScriptsW[i]);
3991 else
3992 FIXME("Unknown elfscript for bit %d\n", i);
3995 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3996 debugstr_w(elf.elfLogFont.lfFaceName),
3997 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3998 csi.ciCharset, type, debugstr_w(elf.elfScript),
3999 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4000 ntm.ntmTm.ntmFlags);
4001 /* release section before callback (FIXME) */
4002 LeaveCriticalSection( &freetype_cs );
4003 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4004 EnterCriticalSection( &freetype_cs );
4008 LeaveCriticalSection( &freetype_cs );
4009 return 1;
4012 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4014 pt->x.value = vec->x >> 6;
4015 pt->x.fract = (vec->x & 0x3f) << 10;
4016 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4017 pt->y.value = vec->y >> 6;
4018 pt->y.fract = (vec->y & 0x3f) << 10;
4019 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4020 return;
4023 /***************************************************
4024 * According to the MSDN documentation on WideCharToMultiByte,
4025 * certain codepages cannot set the default_used parameter.
4026 * This returns TRUE if the codepage can set that parameter, false else
4027 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4029 static BOOL codepage_sets_default_used(UINT codepage)
4031 switch (codepage)
4033 case CP_UTF7:
4034 case CP_UTF8:
4035 case CP_SYMBOL:
4036 return FALSE;
4037 default:
4038 return TRUE;
4043 * GSUB Table handling functions
4046 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4048 const GSUB_CoverageFormat1* cf1;
4050 cf1 = table;
4052 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4054 int count = GET_BE_WORD(cf1->GlyphCount);
4055 int i;
4056 TRACE("Coverage Format 1, %i glyphs\n",count);
4057 for (i = 0; i < count; i++)
4058 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4059 return i;
4060 return -1;
4062 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4064 const GSUB_CoverageFormat2* cf2;
4065 int i;
4066 int count;
4067 cf2 = (GSUB_CoverageFormat2*)cf1;
4069 count = GET_BE_WORD(cf2->RangeCount);
4070 TRACE("Coverage Format 2, %i ranges\n",count);
4071 for (i = 0; i < count; i++)
4073 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4074 return -1;
4075 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4076 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4078 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4079 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4082 return -1;
4084 else
4085 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4087 return -1;
4090 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4092 const GSUB_ScriptList *script;
4093 const GSUB_Script *deflt = NULL;
4094 int i;
4095 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4097 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4098 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4100 const GSUB_Script *scr;
4101 int offset;
4103 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4104 scr = (GSUB_Script*)((LPBYTE)script + offset);
4106 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4107 return scr;
4108 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4109 deflt = scr;
4111 return deflt;
4114 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4116 int i;
4117 int offset;
4118 const GSUB_LangSys *Lang;
4120 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4122 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4124 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4125 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4127 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4128 return Lang;
4130 offset = GET_BE_WORD(script->DefaultLangSys);
4131 if (offset)
4133 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4134 return Lang;
4136 return NULL;
4139 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4141 int i;
4142 const GSUB_FeatureList *feature;
4143 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4145 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4146 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4148 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4149 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4151 const GSUB_Feature *feat;
4152 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4153 return feat;
4156 return NULL;
4159 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4161 int i;
4162 int offset;
4163 const GSUB_LookupList *lookup;
4164 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4166 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4167 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4169 const GSUB_LookupTable *look;
4170 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4171 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4172 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4173 if (GET_BE_WORD(look->LookupType) != 1)
4174 FIXME("We only handle SubType 1\n");
4175 else
4177 int j;
4179 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4181 const GSUB_SingleSubstFormat1 *ssf1;
4182 offset = GET_BE_WORD(look->SubTable[j]);
4183 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4184 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4186 int offset = GET_BE_WORD(ssf1->Coverage);
4187 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4188 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4190 TRACE(" Glyph 0x%x ->",glyph);
4191 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4192 TRACE(" 0x%x\n",glyph);
4195 else
4197 const GSUB_SingleSubstFormat2 *ssf2;
4198 INT index;
4199 INT offset;
4201 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4202 offset = GET_BE_WORD(ssf1->Coverage);
4203 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4204 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4205 TRACE(" Coverage index %i\n",index);
4206 if (index != -1)
4208 TRACE(" Glyph is 0x%x ->",glyph);
4209 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4210 TRACE("0x%x\n",glyph);
4216 return glyph;
4219 static const char* get_opentype_script(const GdiFont *font)
4222 * I am not sure if this is the correct way to generate our script tag
4225 switch (font->charset)
4227 case ANSI_CHARSET: return "latn";
4228 case BALTIC_CHARSET: return "latn"; /* ?? */
4229 case CHINESEBIG5_CHARSET: return "hani";
4230 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4231 case GB2312_CHARSET: return "hani";
4232 case GREEK_CHARSET: return "grek";
4233 case HANGUL_CHARSET: return "hang";
4234 case RUSSIAN_CHARSET: return "cyrl";
4235 case SHIFTJIS_CHARSET: return "kana";
4236 case TURKISH_CHARSET: return "latn"; /* ?? */
4237 case VIETNAMESE_CHARSET: return "latn";
4238 case JOHAB_CHARSET: return "latn"; /* ?? */
4239 case ARABIC_CHARSET: return "arab";
4240 case HEBREW_CHARSET: return "hebr";
4241 case THAI_CHARSET: return "thai";
4242 default: return "latn";
4246 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4248 const GSUB_Header *header;
4249 const GSUB_Script *script;
4250 const GSUB_LangSys *language;
4251 const GSUB_Feature *feature;
4253 if (!font->GSUB_Table)
4254 return glyph;
4256 header = font->GSUB_Table;
4258 script = GSUB_get_script_table(header, get_opentype_script(font));
4259 if (!script)
4261 TRACE("Script not found\n");
4262 return glyph;
4264 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4265 if (!language)
4267 TRACE("Language not found\n");
4268 return glyph;
4270 feature = GSUB_get_feature(header, language, "vrt2");
4271 if (!feature)
4272 feature = GSUB_get_feature(header, language, "vert");
4273 if (!feature)
4275 TRACE("vrt2/vert feature not found\n");
4276 return glyph;
4278 return GSUB_apply_feature(header, feature, glyph);
4281 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4283 FT_UInt glyphId;
4285 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4286 WCHAR wc = (WCHAR)glyph;
4287 BOOL default_used;
4288 BOOL *default_used_pointer;
4289 FT_UInt ret;
4290 char buf;
4291 default_used_pointer = NULL;
4292 default_used = FALSE;
4293 if (codepage_sets_default_used(font->codepage))
4294 default_used_pointer = &default_used;
4295 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4296 ret = 0;
4297 else
4298 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4299 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4300 return get_GSUB_vert_glyph(font,ret);
4303 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4304 glyph = glyph + 0xf000;
4305 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4306 return get_GSUB_vert_glyph(font,glyphId);
4309 /*************************************************************
4310 * WineEngGetGlyphIndices
4313 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4314 LPWORD pgi, DWORD flags)
4316 int i;
4317 int default_char = -1;
4319 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4321 for(i = 0; i < count; i++)
4323 pgi[i] = get_glyph_index(font, lpstr[i]);
4324 if (pgi[i] == 0)
4326 if (default_char == -1)
4328 if (FT_IS_SFNT(font->ft_face))
4330 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4331 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4333 else
4335 TEXTMETRICW textm;
4336 WineEngGetTextMetrics(font, &textm);
4337 default_char = textm.tmDefaultChar;
4340 pgi[i] = default_char;
4343 return count;
4346 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4348 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4349 return !memcmp(matrix, &identity, sizeof(FMAT2));
4352 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4354 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4355 return !memcmp(matrix, &identity, sizeof(MAT2));
4358 /*************************************************************
4359 * WineEngGetGlyphOutline
4361 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4362 * except that the first parameter is the HWINEENGFONT of the font in
4363 * question rather than an HDC.
4366 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4367 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4368 const MAT2* lpmat)
4370 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4371 FT_Face ft_face = incoming_font->ft_face;
4372 GdiFont *font = incoming_font;
4373 FT_UInt glyph_index;
4374 DWORD width, height, pitch, needed = 0;
4375 FT_Bitmap ft_bitmap;
4376 FT_Error err;
4377 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4378 FT_Angle angle = 0;
4379 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4380 double widthRatio = 1.0;
4381 FT_Matrix transMat = identityMat;
4382 FT_Matrix transMatUnrotated;
4383 BOOL needsTransform = FALSE;
4384 BOOL tategaki = (font->GSUB_Table != NULL);
4385 UINT original_index;
4387 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4388 buflen, buf, lpmat);
4390 TRACE("font transform %f %f %f %f\n",
4391 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4392 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4394 GDI_CheckNotLock();
4395 EnterCriticalSection( &freetype_cs );
4397 if(format & GGO_GLYPH_INDEX) {
4398 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4399 original_index = glyph;
4400 format &= ~GGO_GLYPH_INDEX;
4401 } else {
4402 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4403 ft_face = font->ft_face;
4404 original_index = glyph_index;
4407 if(format & GGO_UNHINTED) {
4408 load_flags |= FT_LOAD_NO_HINTING;
4409 format &= ~GGO_UNHINTED;
4412 /* tategaki never appears to happen to lower glyph index */
4413 if (glyph_index < TATEGAKI_LOWER_BOUND )
4414 tategaki = FALSE;
4416 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4417 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4418 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4419 font->gmsize * sizeof(GM*));
4420 } else {
4421 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4422 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4424 *lpgm = FONT_GM(font,original_index)->gm;
4425 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4426 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4427 lpgm->gmCellIncX, lpgm->gmCellIncY);
4428 LeaveCriticalSection( &freetype_cs );
4429 return 1; /* FIXME */
4433 if (!font->gm[original_index / GM_BLOCK_SIZE])
4434 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4436 /* Scaling factor */
4437 if (font->aveWidth)
4439 TEXTMETRICW tm;
4441 WineEngGetTextMetrics(font, &tm);
4443 widthRatio = (double)font->aveWidth;
4444 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4446 else
4447 widthRatio = font->scale_y;
4449 /* Scaling transform */
4450 if (widthRatio != 1.0 || font->scale_y != 1.0)
4452 FT_Matrix scaleMat;
4453 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4454 scaleMat.xy = 0;
4455 scaleMat.yx = 0;
4456 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4458 pFT_Matrix_Multiply(&scaleMat, &transMat);
4459 needsTransform = TRUE;
4462 /* Slant transform */
4463 if (font->fake_italic) {
4464 FT_Matrix slantMat;
4466 slantMat.xx = (1 << 16);
4467 slantMat.xy = ((1 << 16) >> 2);
4468 slantMat.yx = 0;
4469 slantMat.yy = (1 << 16);
4470 pFT_Matrix_Multiply(&slantMat, &transMat);
4471 needsTransform = TRUE;
4474 /* Rotation transform */
4475 transMatUnrotated = transMat;
4476 if(font->orientation && !tategaki) {
4477 FT_Matrix rotationMat;
4478 FT_Vector vecAngle;
4479 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4480 pFT_Vector_Unit(&vecAngle, angle);
4481 rotationMat.xx = vecAngle.x;
4482 rotationMat.xy = -vecAngle.y;
4483 rotationMat.yx = -rotationMat.xy;
4484 rotationMat.yy = rotationMat.xx;
4486 pFT_Matrix_Multiply(&rotationMat, &transMat);
4487 needsTransform = TRUE;
4490 /* World transform */
4491 if (!is_identity_FMAT2(&font->font_desc.matrix))
4493 FT_Matrix worldMat;
4494 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4495 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4496 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4497 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4498 pFT_Matrix_Multiply(&worldMat, &transMat);
4499 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4500 needsTransform = TRUE;
4503 /* Extra transformation specified by caller */
4504 if (!is_identity_MAT2(lpmat))
4506 FT_Matrix extraMat;
4507 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4508 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4509 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4510 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4511 pFT_Matrix_Multiply(&extraMat, &transMat);
4512 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4513 needsTransform = TRUE;
4516 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4517 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4518 format == GGO_GRAY8_BITMAP))
4520 load_flags |= FT_LOAD_NO_BITMAP;
4523 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4525 if(err) {
4526 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4527 LeaveCriticalSection( &freetype_cs );
4528 return GDI_ERROR;
4531 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4532 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4534 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4535 lsb = left >> 6;
4536 bbx = (right - left) >> 6;
4538 if(!needsTransform) {
4539 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4540 bottom = (ft_face->glyph->metrics.horiBearingY -
4541 ft_face->glyph->metrics.height) & -64;
4542 lpgm->gmCellIncX = adv;
4543 lpgm->gmCellIncY = 0;
4544 } else {
4545 INT xc, yc;
4546 FT_Vector vec;
4547 for(xc = 0; xc < 2; xc++) {
4548 for(yc = 0; yc < 2; yc++) {
4549 vec.x = (ft_face->glyph->metrics.horiBearingX +
4550 xc * ft_face->glyph->metrics.width);
4551 vec.y = ft_face->glyph->metrics.horiBearingY -
4552 yc * ft_face->glyph->metrics.height;
4553 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4554 pFT_Vector_Transform(&vec, &transMat);
4555 if(xc == 0 && yc == 0) {
4556 left = right = vec.x;
4557 top = bottom = vec.y;
4558 } else {
4559 if(vec.x < left) left = vec.x;
4560 else if(vec.x > right) right = vec.x;
4561 if(vec.y < bottom) bottom = vec.y;
4562 else if(vec.y > top) top = vec.y;
4566 left = left & -64;
4567 right = (right + 63) & -64;
4568 bottom = bottom & -64;
4569 top = (top + 63) & -64;
4571 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4572 vec.x = ft_face->glyph->metrics.horiAdvance;
4573 vec.y = 0;
4574 pFT_Vector_Transform(&vec, &transMat);
4575 lpgm->gmCellIncX = (vec.x+63) >> 6;
4576 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4578 vec.x = ft_face->glyph->metrics.horiAdvance;
4579 vec.y = 0;
4580 pFT_Vector_Transform(&vec, &transMatUnrotated);
4581 adv = (vec.x+63) >> 6;
4583 lpgm->gmBlackBoxX = (right - left) >> 6;
4584 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4585 lpgm->gmptGlyphOrigin.x = left >> 6;
4586 lpgm->gmptGlyphOrigin.y = top >> 6;
4588 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4589 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4590 lpgm->gmCellIncX, lpgm->gmCellIncY);
4592 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4593 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4595 FONT_GM(font,original_index)->gm = *lpgm;
4596 FONT_GM(font,original_index)->adv = adv;
4597 FONT_GM(font,original_index)->lsb = lsb;
4598 FONT_GM(font,original_index)->bbx = bbx;
4599 FONT_GM(font,original_index)->init = TRUE;
4602 if(format == GGO_METRICS)
4604 LeaveCriticalSection( &freetype_cs );
4605 return 1; /* FIXME */
4608 if(ft_face->glyph->format != ft_glyph_format_outline &&
4609 (format == GGO_NATIVE || format == GGO_BEZIER ||
4610 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4611 format == GGO_GRAY8_BITMAP))
4613 TRACE("loaded a bitmap\n");
4614 LeaveCriticalSection( &freetype_cs );
4615 return GDI_ERROR;
4618 switch(format) {
4619 case GGO_BITMAP:
4620 width = lpgm->gmBlackBoxX;
4621 height = lpgm->gmBlackBoxY;
4622 pitch = ((width + 31) >> 5) << 2;
4623 needed = pitch * height;
4625 if(!buf || !buflen) break;
4627 switch(ft_face->glyph->format) {
4628 case ft_glyph_format_bitmap:
4630 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4631 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4632 INT h = ft_face->glyph->bitmap.rows;
4633 while(h--) {
4634 memcpy(dst, src, w);
4635 src += ft_face->glyph->bitmap.pitch;
4636 dst += pitch;
4638 break;
4641 case ft_glyph_format_outline:
4642 ft_bitmap.width = width;
4643 ft_bitmap.rows = height;
4644 ft_bitmap.pitch = pitch;
4645 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4646 ft_bitmap.buffer = buf;
4648 if(needsTransform)
4649 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4651 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4653 /* Note: FreeType will only set 'black' bits for us. */
4654 memset(buf, 0, needed);
4655 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4656 break;
4658 default:
4659 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4660 LeaveCriticalSection( &freetype_cs );
4661 return GDI_ERROR;
4663 break;
4665 case GGO_GRAY2_BITMAP:
4666 case GGO_GRAY4_BITMAP:
4667 case GGO_GRAY8_BITMAP:
4668 case WINE_GGO_GRAY16_BITMAP:
4670 unsigned int mult, row, col;
4671 BYTE *start, *ptr;
4673 width = lpgm->gmBlackBoxX;
4674 height = lpgm->gmBlackBoxY;
4675 pitch = (width + 3) / 4 * 4;
4676 needed = pitch * height;
4678 if(!buf || !buflen) break;
4680 switch(ft_face->glyph->format) {
4681 case ft_glyph_format_bitmap:
4683 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4684 INT h = ft_face->glyph->bitmap.rows;
4685 INT x;
4686 while(h--) {
4687 for(x = 0; x < pitch; x++)
4689 if(x < ft_face->glyph->bitmap.width)
4690 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4691 else
4692 dst[x] = 0;
4694 src += ft_face->glyph->bitmap.pitch;
4695 dst += pitch;
4697 LeaveCriticalSection( &freetype_cs );
4698 return needed;
4700 case ft_glyph_format_outline:
4702 ft_bitmap.width = width;
4703 ft_bitmap.rows = height;
4704 ft_bitmap.pitch = pitch;
4705 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4706 ft_bitmap.buffer = buf;
4708 if(needsTransform)
4709 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4711 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4713 memset(ft_bitmap.buffer, 0, buflen);
4715 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4717 if(format == GGO_GRAY2_BITMAP)
4718 mult = 4;
4719 else if(format == GGO_GRAY4_BITMAP)
4720 mult = 16;
4721 else if(format == GGO_GRAY8_BITMAP)
4722 mult = 64;
4723 else /* format == WINE_GGO_GRAY16_BITMAP */
4725 LeaveCriticalSection( &freetype_cs );
4726 return needed;
4728 break;
4730 default:
4731 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4732 LeaveCriticalSection( &freetype_cs );
4733 return GDI_ERROR;
4736 start = buf;
4737 for(row = 0; row < height; row++) {
4738 ptr = start;
4739 for(col = 0; col < width; col++, ptr++) {
4740 *ptr = (((int)*ptr) * mult + 128) / 256;
4742 start += pitch;
4744 break;
4747 case WINE_GGO_HRGB_BITMAP:
4748 case WINE_GGO_HBGR_BITMAP:
4749 case WINE_GGO_VRGB_BITMAP:
4750 case WINE_GGO_VBGR_BITMAP:
4751 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4753 switch (ft_face->glyph->format)
4755 case FT_GLYPH_FORMAT_BITMAP:
4757 BYTE *src, *dst;
4758 INT src_pitch, x;
4760 width = lpgm->gmBlackBoxX;
4761 height = lpgm->gmBlackBoxY;
4762 pitch = width * 4;
4763 needed = pitch * height;
4765 if (!buf || !buflen) break;
4767 memset(buf, 0, buflen);
4768 dst = buf;
4769 src = ft_face->glyph->bitmap.buffer;
4770 src_pitch = ft_face->glyph->bitmap.pitch;
4772 while ( height-- )
4774 for (x = 0; x < width; x++)
4776 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4777 ((unsigned int *)dst)[x] = ~0u;
4779 src += src_pitch;
4780 dst += pitch;
4783 break;
4786 case FT_GLYPH_FORMAT_OUTLINE:
4788 unsigned int *dst;
4789 BYTE *src;
4790 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4791 INT x_shift, y_shift;
4792 BOOL rgb;
4793 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4794 FT_Render_Mode render_mode =
4795 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4796 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4798 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4800 if ( render_mode == FT_RENDER_MODE_LCD)
4802 lpgm->gmBlackBoxX += 2;
4803 lpgm->gmptGlyphOrigin.x -= 1;
4805 else
4807 lpgm->gmBlackBoxY += 2;
4808 lpgm->gmptGlyphOrigin.y += 1;
4812 width = lpgm->gmBlackBoxX;
4813 height = lpgm->gmBlackBoxY;
4814 pitch = width * 4;
4815 needed = pitch * height;
4817 if (!buf || !buflen) break;
4819 memset(buf, 0, buflen);
4820 dst = buf;
4821 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
4823 if ( needsTransform )
4824 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
4826 if ( pFT_Library_SetLcdFilter )
4827 pFT_Library_SetLcdFilter( library, lcdfilter );
4828 pFT_Render_Glyph (ft_face->glyph, render_mode);
4830 src = ft_face->glyph->bitmap.buffer;
4831 src_pitch = ft_face->glyph->bitmap.pitch;
4832 src_width = ft_face->glyph->bitmap.width;
4833 src_height = ft_face->glyph->bitmap.rows;
4835 if ( render_mode == FT_RENDER_MODE_LCD)
4837 rgb_interval = 1;
4838 hmul = 3;
4839 vmul = 1;
4841 else
4843 rgb_interval = src_pitch;
4844 hmul = 1;
4845 vmul = 3;
4848 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
4849 if ( x_shift < 0 ) x_shift = 0;
4850 if ( x_shift + (src_width / hmul) > width )
4851 x_shift = width - (src_width / hmul);
4853 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
4854 if ( y_shift < 0 ) y_shift = 0;
4855 if ( y_shift + (src_height / vmul) > height )
4856 y_shift = height - (src_height / vmul);
4858 dst += x_shift + y_shift * ( pitch / 4 );
4859 while ( src_height )
4861 for ( x = 0; x < src_width / hmul; x++ )
4863 if ( rgb )
4865 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
4866 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4867 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
4868 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4870 else
4872 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
4873 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
4874 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
4875 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
4878 src += src_pitch * vmul;
4879 dst += pitch / 4;
4880 src_height -= vmul;
4883 break;
4886 default:
4887 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
4888 LeaveCriticalSection ( &freetype_cs );
4889 return GDI_ERROR;
4892 break;
4894 #else
4895 LeaveCriticalSection( &freetype_cs );
4896 return GDI_ERROR;
4897 #endif
4899 case GGO_NATIVE:
4901 int contour, point = 0, first_pt;
4902 FT_Outline *outline = &ft_face->glyph->outline;
4903 TTPOLYGONHEADER *pph;
4904 TTPOLYCURVE *ppc;
4905 DWORD pph_start, cpfx, type;
4907 if(buflen == 0) buf = NULL;
4909 if (needsTransform && buf) {
4910 pFT_Outline_Transform(outline, &transMat);
4913 for(contour = 0; contour < outline->n_contours; contour++) {
4914 pph_start = needed;
4915 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4916 first_pt = point;
4917 if(buf) {
4918 pph->dwType = TT_POLYGON_TYPE;
4919 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4921 needed += sizeof(*pph);
4922 point++;
4923 while(point <= outline->contours[contour]) {
4924 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4925 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4926 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4927 cpfx = 0;
4928 do {
4929 if(buf)
4930 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4931 cpfx++;
4932 point++;
4933 } while(point <= outline->contours[contour] &&
4934 (outline->tags[point] & FT_Curve_Tag_On) ==
4935 (outline->tags[point-1] & FT_Curve_Tag_On));
4936 /* At the end of a contour Windows adds the start point, but
4937 only for Beziers */
4938 if(point > outline->contours[contour] &&
4939 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4940 if(buf)
4941 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4942 cpfx++;
4943 } else if(point <= outline->contours[contour] &&
4944 outline->tags[point] & FT_Curve_Tag_On) {
4945 /* add closing pt for bezier */
4946 if(buf)
4947 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4948 cpfx++;
4949 point++;
4951 if(buf) {
4952 ppc->wType = type;
4953 ppc->cpfx = cpfx;
4955 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4957 if(buf)
4958 pph->cb = needed - pph_start;
4960 break;
4962 case GGO_BEZIER:
4964 /* Convert the quadratic Beziers to cubic Beziers.
4965 The parametric eqn for a cubic Bezier is, from PLRM:
4966 r(t) = at^3 + bt^2 + ct + r0
4967 with the control points:
4968 r1 = r0 + c/3
4969 r2 = r1 + (c + b)/3
4970 r3 = r0 + c + b + a
4972 A quadratic Beizer has the form:
4973 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4975 So equating powers of t leads to:
4976 r1 = 2/3 p1 + 1/3 p0
4977 r2 = 2/3 p1 + 1/3 p2
4978 and of course r0 = p0, r3 = p2
4981 int contour, point = 0, first_pt;
4982 FT_Outline *outline = &ft_face->glyph->outline;
4983 TTPOLYGONHEADER *pph;
4984 TTPOLYCURVE *ppc;
4985 DWORD pph_start, cpfx, type;
4986 FT_Vector cubic_control[4];
4987 if(buflen == 0) buf = NULL;
4989 if (needsTransform && buf) {
4990 pFT_Outline_Transform(outline, &transMat);
4993 for(contour = 0; contour < outline->n_contours; contour++) {
4994 pph_start = needed;
4995 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4996 first_pt = point;
4997 if(buf) {
4998 pph->dwType = TT_POLYGON_TYPE;
4999 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5001 needed += sizeof(*pph);
5002 point++;
5003 while(point <= outline->contours[contour]) {
5004 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5005 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5006 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5007 cpfx = 0;
5008 do {
5009 if(type == TT_PRIM_LINE) {
5010 if(buf)
5011 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5012 cpfx++;
5013 point++;
5014 } else {
5015 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5016 so cpfx = 3n */
5018 /* FIXME: Possible optimization in endpoint calculation
5019 if there are two consecutive curves */
5020 cubic_control[0] = outline->points[point-1];
5021 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5022 cubic_control[0].x += outline->points[point].x + 1;
5023 cubic_control[0].y += outline->points[point].y + 1;
5024 cubic_control[0].x >>= 1;
5025 cubic_control[0].y >>= 1;
5027 if(point+1 > outline->contours[contour])
5028 cubic_control[3] = outline->points[first_pt];
5029 else {
5030 cubic_control[3] = outline->points[point+1];
5031 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5032 cubic_control[3].x += outline->points[point].x + 1;
5033 cubic_control[3].y += outline->points[point].y + 1;
5034 cubic_control[3].x >>= 1;
5035 cubic_control[3].y >>= 1;
5038 /* r1 = 1/3 p0 + 2/3 p1
5039 r2 = 1/3 p2 + 2/3 p1 */
5040 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5041 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5042 cubic_control[2] = cubic_control[1];
5043 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5044 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5045 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5046 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5047 if(buf) {
5048 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5049 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5050 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5052 cpfx += 3;
5053 point++;
5055 } while(point <= outline->contours[contour] &&
5056 (outline->tags[point] & FT_Curve_Tag_On) ==
5057 (outline->tags[point-1] & FT_Curve_Tag_On));
5058 /* At the end of a contour Windows adds the start point,
5059 but only for Beziers and we've already done that.
5061 if(point <= outline->contours[contour] &&
5062 outline->tags[point] & FT_Curve_Tag_On) {
5063 /* This is the closing pt of a bezier, but we've already
5064 added it, so just inc point and carry on */
5065 point++;
5067 if(buf) {
5068 ppc->wType = type;
5069 ppc->cpfx = cpfx;
5071 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5073 if(buf)
5074 pph->cb = needed - pph_start;
5076 break;
5079 default:
5080 FIXME("Unsupported format %d\n", format);
5081 LeaveCriticalSection( &freetype_cs );
5082 return GDI_ERROR;
5084 LeaveCriticalSection( &freetype_cs );
5085 return needed;
5088 static BOOL get_bitmap_text_metrics(GdiFont *font)
5090 FT_Face ft_face = font->ft_face;
5091 #ifdef HAVE_FREETYPE_FTWINFNT_H
5092 FT_WinFNT_HeaderRec winfnt_header;
5093 #endif
5094 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5095 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5096 font->potm->otmSize = size;
5098 #define TM font->potm->otmTextMetrics
5099 #ifdef HAVE_FREETYPE_FTWINFNT_H
5100 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5102 TM.tmHeight = winfnt_header.pixel_height;
5103 TM.tmAscent = winfnt_header.ascent;
5104 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5105 TM.tmInternalLeading = winfnt_header.internal_leading;
5106 TM.tmExternalLeading = winfnt_header.external_leading;
5107 TM.tmAveCharWidth = winfnt_header.avg_width;
5108 TM.tmMaxCharWidth = winfnt_header.max_width;
5109 TM.tmWeight = winfnt_header.weight;
5110 TM.tmOverhang = 0;
5111 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5112 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5113 TM.tmFirstChar = winfnt_header.first_char;
5114 TM.tmLastChar = winfnt_header.last_char;
5115 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5116 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5117 TM.tmItalic = winfnt_header.italic;
5118 TM.tmUnderlined = font->underline;
5119 TM.tmStruckOut = font->strikeout;
5120 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5121 TM.tmCharSet = winfnt_header.charset;
5123 else
5124 #endif
5126 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5127 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5128 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5129 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5130 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5131 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5132 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5133 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5134 TM.tmOverhang = 0;
5135 TM.tmDigitizedAspectX = 96; /* FIXME */
5136 TM.tmDigitizedAspectY = 96; /* FIXME */
5137 TM.tmFirstChar = 1;
5138 TM.tmLastChar = 255;
5139 TM.tmDefaultChar = 32;
5140 TM.tmBreakChar = 32;
5141 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5142 TM.tmUnderlined = font->underline;
5143 TM.tmStruckOut = font->strikeout;
5144 /* NB inverted meaning of TMPF_FIXED_PITCH */
5145 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5146 TM.tmCharSet = font->charset;
5148 #undef TM
5150 return TRUE;
5154 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5156 double scale_x, scale_y;
5158 if (font->aveWidth)
5160 scale_x = (double)font->aveWidth;
5161 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5163 else
5164 scale_x = font->scale_y;
5166 scale_x *= fabs(font->font_desc.matrix.eM11);
5167 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5169 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5170 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5172 SCALE_Y(ptm->tmHeight);
5173 SCALE_Y(ptm->tmAscent);
5174 SCALE_Y(ptm->tmDescent);
5175 SCALE_Y(ptm->tmInternalLeading);
5176 SCALE_Y(ptm->tmExternalLeading);
5177 SCALE_Y(ptm->tmOverhang);
5179 SCALE_X(ptm->tmAveCharWidth);
5180 SCALE_X(ptm->tmMaxCharWidth);
5182 #undef SCALE_X
5183 #undef SCALE_Y
5186 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5188 double scale_x, scale_y;
5190 if (font->aveWidth)
5192 scale_x = (double)font->aveWidth;
5193 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5195 else
5196 scale_x = font->scale_y;
5198 scale_x *= fabs(font->font_desc.matrix.eM11);
5199 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5201 scale_font_metrics(font, &potm->otmTextMetrics);
5203 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5204 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5206 SCALE_Y(potm->otmAscent);
5207 SCALE_Y(potm->otmDescent);
5208 SCALE_Y(potm->otmLineGap);
5209 SCALE_Y(potm->otmsCapEmHeight);
5210 SCALE_Y(potm->otmsXHeight);
5211 SCALE_Y(potm->otmrcFontBox.top);
5212 SCALE_Y(potm->otmrcFontBox.bottom);
5213 SCALE_X(potm->otmrcFontBox.left);
5214 SCALE_X(potm->otmrcFontBox.right);
5215 SCALE_Y(potm->otmMacAscent);
5216 SCALE_Y(potm->otmMacDescent);
5217 SCALE_Y(potm->otmMacLineGap);
5218 SCALE_X(potm->otmptSubscriptSize.x);
5219 SCALE_Y(potm->otmptSubscriptSize.y);
5220 SCALE_X(potm->otmptSubscriptOffset.x);
5221 SCALE_Y(potm->otmptSubscriptOffset.y);
5222 SCALE_X(potm->otmptSuperscriptSize.x);
5223 SCALE_Y(potm->otmptSuperscriptSize.y);
5224 SCALE_X(potm->otmptSuperscriptOffset.x);
5225 SCALE_Y(potm->otmptSuperscriptOffset.y);
5226 SCALE_Y(potm->otmsStrikeoutSize);
5227 SCALE_Y(potm->otmsStrikeoutPosition);
5228 SCALE_Y(potm->otmsUnderscoreSize);
5229 SCALE_Y(potm->otmsUnderscorePosition);
5231 #undef SCALE_X
5232 #undef SCALE_Y
5235 /*************************************************************
5236 * WineEngGetTextMetrics
5239 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5241 GDI_CheckNotLock();
5242 EnterCriticalSection( &freetype_cs );
5243 if(!font->potm) {
5244 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5245 if(!get_bitmap_text_metrics(font))
5247 LeaveCriticalSection( &freetype_cs );
5248 return FALSE;
5251 if(!font->potm)
5253 LeaveCriticalSection( &freetype_cs );
5254 return FALSE;
5256 *ptm = font->potm->otmTextMetrics;
5257 scale_font_metrics(font, ptm);
5258 LeaveCriticalSection( &freetype_cs );
5259 return TRUE;
5262 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5264 int i;
5266 for(i = 0; i < ft_face->num_charmaps; i++)
5268 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5269 return TRUE;
5271 return FALSE;
5274 /*************************************************************
5275 * WineEngGetOutlineTextMetrics
5278 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5279 OUTLINETEXTMETRICW *potm)
5281 FT_Face ft_face = font->ft_face;
5282 UINT needed, lenfam, lensty, ret;
5283 TT_OS2 *pOS2;
5284 TT_HoriHeader *pHori;
5285 TT_Postscript *pPost;
5286 FT_Fixed x_scale, y_scale;
5287 WCHAR *family_nameW, *style_nameW;
5288 static const WCHAR spaceW[] = {' ', '\0'};
5289 char *cp;
5290 INT ascent, descent;
5292 TRACE("font=%p\n", font);
5294 if(!FT_IS_SCALABLE(ft_face))
5295 return 0;
5297 GDI_CheckNotLock();
5298 EnterCriticalSection( &freetype_cs );
5300 if(font->potm) {
5301 if(cbSize >= font->potm->otmSize)
5303 memcpy(potm, font->potm, font->potm->otmSize);
5304 scale_outline_font_metrics(font, potm);
5306 LeaveCriticalSection( &freetype_cs );
5307 return font->potm->otmSize;
5311 needed = sizeof(*potm);
5313 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5314 family_nameW = strdupW(font->name);
5316 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5317 * sizeof(WCHAR);
5318 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5319 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5320 style_nameW, lensty/sizeof(WCHAR));
5322 /* These names should be read from the TT name table */
5324 /* length of otmpFamilyName */
5325 needed += lenfam;
5327 /* length of otmpFaceName */
5328 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5329 needed += lenfam; /* just the family name */
5330 } else {
5331 needed += lenfam + lensty; /* family + " " + style */
5334 /* length of otmpStyleName */
5335 needed += lensty;
5337 /* length of otmpFullName */
5338 needed += lenfam + lensty;
5341 x_scale = ft_face->size->metrics.x_scale;
5342 y_scale = ft_face->size->metrics.y_scale;
5344 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5345 if(!pOS2) {
5346 FIXME("Can't find OS/2 table - not TT font?\n");
5347 ret = 0;
5348 goto end;
5351 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5352 if(!pHori) {
5353 FIXME("Can't find HHEA table - not TT font?\n");
5354 ret = 0;
5355 goto end;
5358 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5360 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",
5361 pOS2->usWinAscent, pOS2->usWinDescent,
5362 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5363 ft_face->ascender, ft_face->descender, ft_face->height,
5364 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5365 ft_face->bbox.yMax, ft_face->bbox.yMin);
5367 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5368 font->potm->otmSize = needed;
5370 #define TM font->potm->otmTextMetrics
5372 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5373 ascent = pHori->Ascender;
5374 descent = -pHori->Descender;
5375 } else {
5376 ascent = pOS2->usWinAscent;
5377 descent = pOS2->usWinDescent;
5380 if(font->yMax) {
5381 TM.tmAscent = font->yMax;
5382 TM.tmDescent = -font->yMin;
5383 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5384 } else {
5385 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5386 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5387 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5388 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5391 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5393 /* MSDN says:
5394 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5396 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5397 ((ascent + descent) -
5398 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5400 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5401 if (TM.tmAveCharWidth == 0) {
5402 TM.tmAveCharWidth = 1;
5404 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5405 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5406 TM.tmOverhang = 0;
5407 TM.tmDigitizedAspectX = 300;
5408 TM.tmDigitizedAspectY = 300;
5409 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5410 * symbol range to 0 - f0ff
5413 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5415 TM.tmFirstChar = 0;
5416 switch(GetACP())
5418 case 1257: /* Baltic */
5419 TM.tmLastChar = 0xf8fd;
5420 break;
5421 default:
5422 TM.tmLastChar = 0xf0ff;
5424 TM.tmBreakChar = 0x20;
5425 TM.tmDefaultChar = 0x1f;
5427 else
5429 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5430 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5432 if(pOS2->usFirstCharIndex <= 1)
5433 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5434 else if (pOS2->usFirstCharIndex > 0xff)
5435 TM.tmBreakChar = 0x20;
5436 else
5437 TM.tmBreakChar = pOS2->usFirstCharIndex;
5438 TM.tmDefaultChar = TM.tmBreakChar - 1;
5440 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5441 TM.tmUnderlined = font->underline;
5442 TM.tmStruckOut = font->strikeout;
5444 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5445 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5446 (pOS2->version == 0xFFFFU ||
5447 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5448 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5449 else
5450 TM.tmPitchAndFamily = 0;
5452 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5454 case PAN_FAMILY_SCRIPT:
5455 TM.tmPitchAndFamily |= FF_SCRIPT;
5456 break;
5458 case PAN_FAMILY_DECORATIVE:
5459 TM.tmPitchAndFamily |= FF_DECORATIVE;
5460 break;
5462 case PAN_ANY:
5463 case PAN_NO_FIT:
5464 case PAN_FAMILY_TEXT_DISPLAY:
5465 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5466 /* which is clearly not what the panose spec says. */
5467 default:
5468 if(TM.tmPitchAndFamily == 0 || /* fixed */
5469 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5470 TM.tmPitchAndFamily = FF_MODERN;
5471 else
5473 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5475 case PAN_ANY:
5476 case PAN_NO_FIT:
5477 default:
5478 TM.tmPitchAndFamily |= FF_DONTCARE;
5479 break;
5481 case PAN_SERIF_COVE:
5482 case PAN_SERIF_OBTUSE_COVE:
5483 case PAN_SERIF_SQUARE_COVE:
5484 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5485 case PAN_SERIF_SQUARE:
5486 case PAN_SERIF_THIN:
5487 case PAN_SERIF_BONE:
5488 case PAN_SERIF_EXAGGERATED:
5489 case PAN_SERIF_TRIANGLE:
5490 TM.tmPitchAndFamily |= FF_ROMAN;
5491 break;
5493 case PAN_SERIF_NORMAL_SANS:
5494 case PAN_SERIF_OBTUSE_SANS:
5495 case PAN_SERIF_PERP_SANS:
5496 case PAN_SERIF_FLARED:
5497 case PAN_SERIF_ROUNDED:
5498 TM.tmPitchAndFamily |= FF_SWISS;
5499 break;
5502 break;
5505 if(FT_IS_SCALABLE(ft_face))
5506 TM.tmPitchAndFamily |= TMPF_VECTOR;
5508 if(FT_IS_SFNT(ft_face))
5510 if (font->ntmFlags & NTM_PS_OPENTYPE)
5511 TM.tmPitchAndFamily |= TMPF_DEVICE;
5512 else
5513 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5516 TM.tmCharSet = font->charset;
5518 font->potm->otmFiller = 0;
5519 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5520 font->potm->otmfsSelection = pOS2->fsSelection;
5521 font->potm->otmfsType = pOS2->fsType;
5522 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5523 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5524 font->potm->otmItalicAngle = 0; /* POST table */
5525 font->potm->otmEMSquare = ft_face->units_per_EM;
5526 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5527 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5528 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5529 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5530 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5531 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5532 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5533 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5534 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5535 font->potm->otmMacAscent = TM.tmAscent;
5536 font->potm->otmMacDescent = -TM.tmDescent;
5537 font->potm->otmMacLineGap = font->potm->otmLineGap;
5538 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5539 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5540 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5541 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5542 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5543 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5544 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5545 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5546 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5547 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5548 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5549 if(!pPost) {
5550 font->potm->otmsUnderscoreSize = 0;
5551 font->potm->otmsUnderscorePosition = 0;
5552 } else {
5553 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5554 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5556 #undef TM
5558 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5559 cp = (char*)font->potm + sizeof(*font->potm);
5560 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5561 strcpyW((WCHAR*)cp, family_nameW);
5562 cp += lenfam;
5563 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5564 strcpyW((WCHAR*)cp, style_nameW);
5565 cp += lensty;
5566 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5567 strcpyW((WCHAR*)cp, family_nameW);
5568 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5569 strcatW((WCHAR*)cp, spaceW);
5570 strcatW((WCHAR*)cp, style_nameW);
5571 cp += lenfam + lensty;
5572 } else
5573 cp += lenfam;
5574 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5575 strcpyW((WCHAR*)cp, family_nameW);
5576 strcatW((WCHAR*)cp, spaceW);
5577 strcatW((WCHAR*)cp, style_nameW);
5578 ret = needed;
5580 if(potm && needed <= cbSize)
5582 memcpy(potm, font->potm, font->potm->otmSize);
5583 scale_outline_font_metrics(font, potm);
5586 end:
5587 HeapFree(GetProcessHeap(), 0, style_nameW);
5588 HeapFree(GetProcessHeap(), 0, family_nameW);
5590 LeaveCriticalSection( &freetype_cs );
5591 return ret;
5594 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5596 HFONTLIST *hfontlist;
5597 child->font = alloc_font();
5598 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5599 if(!child->font->ft_face)
5601 free_font(child->font);
5602 child->font = NULL;
5603 return FALSE;
5606 child->font->font_desc = font->font_desc;
5607 child->font->ntmFlags = child->face->ntmFlags;
5608 child->font->orientation = font->orientation;
5609 child->font->scale_y = font->scale_y;
5610 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5611 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5612 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5613 child->font->base_font = font;
5614 list_add_head(&child_font_list, &child->font->entry);
5615 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5616 return TRUE;
5619 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5621 FT_UInt g;
5622 CHILD_FONT *child_font;
5624 if(font->base_font)
5625 font = font->base_font;
5627 *linked_font = font;
5629 if((*glyph = get_glyph_index(font, c)))
5630 return TRUE;
5632 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5634 if(!child_font->font)
5635 if(!load_child_font(font, child_font))
5636 continue;
5638 if(!child_font->font->ft_face)
5639 continue;
5640 g = get_glyph_index(child_font->font, c);
5641 if(g)
5643 *glyph = g;
5644 *linked_font = child_font->font;
5645 return TRUE;
5648 return FALSE;
5651 /*************************************************************
5652 * WineEngGetCharWidth
5655 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5656 LPINT buffer)
5658 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5659 UINT c;
5660 GLYPHMETRICS gm;
5661 FT_UInt glyph_index;
5662 GdiFont *linked_font;
5664 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5666 GDI_CheckNotLock();
5667 EnterCriticalSection( &freetype_cs );
5668 for(c = firstChar; c <= lastChar; c++) {
5669 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5670 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5671 &gm, 0, NULL, &identity);
5672 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5674 LeaveCriticalSection( &freetype_cs );
5675 return TRUE;
5678 /*************************************************************
5679 * WineEngGetCharABCWidths
5682 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5683 LPABC buffer)
5685 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5686 UINT c;
5687 GLYPHMETRICS gm;
5688 FT_UInt glyph_index;
5689 GdiFont *linked_font;
5691 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5693 if(!FT_IS_SCALABLE(font->ft_face))
5694 return FALSE;
5696 GDI_CheckNotLock();
5697 EnterCriticalSection( &freetype_cs );
5699 for(c = firstChar; c <= lastChar; c++) {
5700 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5701 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5702 &gm, 0, NULL, &identity);
5703 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5704 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5705 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5706 FONT_GM(linked_font,glyph_index)->bbx;
5708 LeaveCriticalSection( &freetype_cs );
5709 return TRUE;
5712 /*************************************************************
5713 * WineEngGetCharABCWidthsI
5716 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5717 LPABC buffer)
5719 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5720 UINT c;
5721 GLYPHMETRICS gm;
5722 FT_UInt glyph_index;
5723 GdiFont *linked_font;
5725 if(!FT_HAS_HORIZONTAL(font->ft_face))
5726 return FALSE;
5728 GDI_CheckNotLock();
5729 EnterCriticalSection( &freetype_cs );
5731 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5732 if (!pgi)
5733 for(c = firstChar; c < firstChar+count; c++) {
5734 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5735 &gm, 0, NULL, &identity);
5736 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5737 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5738 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5739 - FONT_GM(linked_font,c)->bbx;
5741 else
5742 for(c = 0; c < count; c++) {
5743 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5744 &gm, 0, NULL, &identity);
5745 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5746 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5747 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5748 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5751 LeaveCriticalSection( &freetype_cs );
5752 return TRUE;
5755 /*************************************************************
5756 * WineEngGetTextExtentExPoint
5759 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5760 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5762 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5763 INT idx;
5764 INT nfit = 0, ext;
5765 GLYPHMETRICS gm;
5766 TEXTMETRICW tm;
5767 FT_UInt glyph_index;
5768 GdiFont *linked_font;
5770 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5771 max_ext, size);
5773 GDI_CheckNotLock();
5774 EnterCriticalSection( &freetype_cs );
5776 size->cx = 0;
5777 WineEngGetTextMetrics(font, &tm);
5778 size->cy = tm.tmHeight;
5780 for(idx = 0; idx < count; idx++) {
5781 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5782 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5783 &gm, 0, NULL, &identity);
5784 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5785 ext = size->cx;
5786 if (! pnfit || ext <= max_ext) {
5787 ++nfit;
5788 if (dxs)
5789 dxs[idx] = ext;
5793 if (pnfit)
5794 *pnfit = nfit;
5796 LeaveCriticalSection( &freetype_cs );
5797 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5798 return TRUE;
5801 /*************************************************************
5802 * WineEngGetTextExtentExPointI
5805 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5806 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5808 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5809 INT idx;
5810 INT nfit = 0, ext;
5811 GLYPHMETRICS gm;
5812 TEXTMETRICW tm;
5814 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5816 GDI_CheckNotLock();
5817 EnterCriticalSection( &freetype_cs );
5819 size->cx = 0;
5820 WineEngGetTextMetrics(font, &tm);
5821 size->cy = tm.tmHeight;
5823 for(idx = 0; idx < count; idx++) {
5824 WineEngGetGlyphOutline(font, indices[idx],
5825 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5826 &identity);
5827 size->cx += FONT_GM(font,indices[idx])->adv;
5828 ext = size->cx;
5829 if (! pnfit || ext <= max_ext) {
5830 ++nfit;
5831 if (dxs)
5832 dxs[idx] = ext;
5836 if (pnfit)
5837 *pnfit = nfit;
5839 LeaveCriticalSection( &freetype_cs );
5840 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5841 return TRUE;
5844 /*************************************************************
5845 * WineEngGetFontData
5848 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5849 DWORD cbData)
5851 FT_Face ft_face = font->ft_face;
5852 FT_ULong len;
5853 FT_Error err;
5855 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5856 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5857 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5859 if(!FT_IS_SFNT(ft_face))
5860 return GDI_ERROR;
5862 if(!buf || !cbData)
5863 len = 0;
5864 else
5865 len = cbData;
5867 if(table) { /* MS tags differ in endianness from FT ones */
5868 table = table >> 24 | table << 24 |
5869 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5872 /* make sure value of len is the value freetype says it needs */
5873 if(buf && len)
5875 FT_ULong needed = 0;
5876 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5877 if( !err && needed < len) len = needed;
5879 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5881 if(err) {
5882 TRACE("Can't find table %c%c%c%c\n",
5883 /* bytes were reversed */
5884 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5885 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5886 return GDI_ERROR;
5888 return len;
5891 /*************************************************************
5892 * WineEngGetTextFace
5895 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5897 INT n = strlenW(font->name) + 1;
5898 if(str) {
5899 lstrcpynW(str, font->name, count);
5900 return min(count, n);
5901 } else
5902 return n;
5905 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5907 if (fs) *fs = font->fs;
5908 return font->charset;
5911 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5913 GdiFont *font = dc->gdiFont, *linked_font;
5914 struct list *first_hfont;
5915 BOOL ret;
5917 GDI_CheckNotLock();
5918 EnterCriticalSection( &freetype_cs );
5919 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5920 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5921 if(font == linked_font)
5922 *new_hfont = dc->hFont;
5923 else
5925 first_hfont = list_head(&linked_font->hfontlist);
5926 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5928 LeaveCriticalSection( &freetype_cs );
5929 return ret;
5932 /* Retrieve a list of supported Unicode ranges for a given font.
5933 * Can be called with NULL gs to calculate the buffer size. Returns
5934 * the number of ranges found.
5936 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5938 DWORD num_ranges = 0;
5940 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5942 FT_UInt glyph_code;
5943 FT_ULong char_code, char_code_prev;
5945 glyph_code = 0;
5946 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5948 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5949 face->num_glyphs, glyph_code, char_code);
5951 if (!glyph_code) return 0;
5953 if (gs)
5955 gs->ranges[0].wcLow = (USHORT)char_code;
5956 gs->ranges[0].cGlyphs = 0;
5957 gs->cGlyphsSupported = 0;
5960 num_ranges = 1;
5961 while (glyph_code)
5963 if (char_code < char_code_prev)
5965 ERR("expected increasing char code from FT_Get_Next_Char\n");
5966 return 0;
5968 if (char_code - char_code_prev > 1)
5970 num_ranges++;
5971 if (gs)
5973 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5974 gs->ranges[num_ranges - 1].cGlyphs = 1;
5975 gs->cGlyphsSupported++;
5978 else if (gs)
5980 gs->ranges[num_ranges - 1].cGlyphs++;
5981 gs->cGlyphsSupported++;
5983 char_code_prev = char_code;
5984 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5987 else
5988 FIXME("encoding %u not supported\n", face->charmap->encoding);
5990 return num_ranges;
5993 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5995 DWORD size = 0;
5996 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5998 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5999 if (glyphset)
6001 glyphset->cbThis = size;
6002 glyphset->cRanges = num_ranges;
6004 return size;
6007 /*************************************************************
6008 * FontIsLinked
6010 BOOL WineEngFontIsLinked(GdiFont *font)
6012 BOOL ret;
6013 GDI_CheckNotLock();
6014 EnterCriticalSection( &freetype_cs );
6015 ret = !list_empty(&font->child_fonts);
6016 LeaveCriticalSection( &freetype_cs );
6017 return ret;
6020 static BOOL is_hinting_enabled(void)
6022 /* Use the >= 2.2.0 function if available */
6023 if(pFT_Get_TrueType_Engine_Type)
6025 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6026 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6028 #ifdef FT_DRIVER_HAS_HINTER
6029 else
6031 FT_Module mod;
6033 /* otherwise if we've been compiled with < 2.2.0 headers
6034 use the internal macro */
6035 mod = pFT_Get_Module(library, "truetype");
6036 if(mod && FT_DRIVER_HAS_HINTER(mod))
6037 return TRUE;
6039 #endif
6041 return FALSE;
6044 static BOOL is_subpixel_rendering_enabled( void )
6046 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6047 return pFT_Library_SetLcdFilter &&
6048 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6049 #else
6050 return FALSE;
6051 #endif
6054 /*************************************************************************
6055 * GetRasterizerCaps (GDI32.@)
6057 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6059 static int hinting = -1;
6060 static int subpixel = -1;
6062 if(hinting == -1)
6064 hinting = is_hinting_enabled();
6065 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6068 if ( subpixel == -1 )
6070 subpixel = is_subpixel_rendering_enabled();
6071 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6074 lprs->nSize = sizeof(RASTERIZER_STATUS);
6075 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6076 if ( subpixel )
6077 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6078 lprs->nLanguageID = 0;
6079 return TRUE;
6082 /*************************************************************
6083 * WineEngRealizationInfo
6085 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6087 FIXME("(%p, %p): stub!\n", font, info);
6089 info->flags = 1;
6090 if(FT_IS_SCALABLE(font->ft_face))
6091 info->flags |= 2;
6093 info->cache_num = font->cache_num;
6094 info->unknown2 = -1;
6095 return TRUE;
6098 /*************************************************************************
6099 * Kerning support for TrueType fonts
6101 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6103 struct TT_kern_table
6105 USHORT version;
6106 USHORT nTables;
6109 struct TT_kern_subtable
6111 USHORT version;
6112 USHORT length;
6113 union
6115 USHORT word;
6116 struct
6118 USHORT horizontal : 1;
6119 USHORT minimum : 1;
6120 USHORT cross_stream: 1;
6121 USHORT override : 1;
6122 USHORT reserved1 : 4;
6123 USHORT format : 8;
6124 } bits;
6125 } coverage;
6128 struct TT_format0_kern_subtable
6130 USHORT nPairs;
6131 USHORT searchRange;
6132 USHORT entrySelector;
6133 USHORT rangeShift;
6136 struct TT_kern_pair
6138 USHORT left;
6139 USHORT right;
6140 short value;
6143 static DWORD parse_format0_kern_subtable(GdiFont *font,
6144 const struct TT_format0_kern_subtable *tt_f0_ks,
6145 const USHORT *glyph_to_char,
6146 KERNINGPAIR *kern_pair, DWORD cPairs)
6148 USHORT i, nPairs;
6149 const struct TT_kern_pair *tt_kern_pair;
6151 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6153 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6155 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6156 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6157 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6159 if (!kern_pair || !cPairs)
6160 return nPairs;
6162 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6164 nPairs = min(nPairs, cPairs);
6166 for (i = 0; i < nPairs; i++)
6168 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6169 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6170 /* this algorithm appears to better match what Windows does */
6171 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6172 if (kern_pair->iKernAmount < 0)
6174 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6175 kern_pair->iKernAmount -= font->ppem;
6177 else if (kern_pair->iKernAmount > 0)
6179 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6180 kern_pair->iKernAmount += font->ppem;
6182 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6184 TRACE("left %u right %u value %d\n",
6185 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6187 kern_pair++;
6189 TRACE("copied %u entries\n", nPairs);
6190 return nPairs;
6193 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6195 DWORD length;
6196 void *buf;
6197 const struct TT_kern_table *tt_kern_table;
6198 const struct TT_kern_subtable *tt_kern_subtable;
6199 USHORT i, nTables;
6200 USHORT *glyph_to_char;
6202 GDI_CheckNotLock();
6203 EnterCriticalSection( &freetype_cs );
6204 if (font->total_kern_pairs != (DWORD)-1)
6206 if (cPairs && kern_pair)
6208 cPairs = min(cPairs, font->total_kern_pairs);
6209 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6210 LeaveCriticalSection( &freetype_cs );
6211 return cPairs;
6213 LeaveCriticalSection( &freetype_cs );
6214 return font->total_kern_pairs;
6217 font->total_kern_pairs = 0;
6219 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6221 if (length == GDI_ERROR)
6223 TRACE("no kerning data in the font\n");
6224 LeaveCriticalSection( &freetype_cs );
6225 return 0;
6228 buf = HeapAlloc(GetProcessHeap(), 0, length);
6229 if (!buf)
6231 WARN("Out of memory\n");
6232 LeaveCriticalSection( &freetype_cs );
6233 return 0;
6236 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6238 /* build a glyph index to char code map */
6239 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6240 if (!glyph_to_char)
6242 WARN("Out of memory allocating a glyph index to char code map\n");
6243 HeapFree(GetProcessHeap(), 0, buf);
6244 LeaveCriticalSection( &freetype_cs );
6245 return 0;
6248 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6250 FT_UInt glyph_code;
6251 FT_ULong char_code;
6253 glyph_code = 0;
6254 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6256 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6257 font->ft_face->num_glyphs, glyph_code, char_code);
6259 while (glyph_code)
6261 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6263 /* FIXME: This doesn't match what Windows does: it does some fancy
6264 * things with duplicate glyph index to char code mappings, while
6265 * we just avoid overriding existing entries.
6267 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6268 glyph_to_char[glyph_code] = (USHORT)char_code;
6270 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6273 else
6275 ULONG n;
6277 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6278 for (n = 0; n <= 65535; n++)
6279 glyph_to_char[n] = (USHORT)n;
6282 tt_kern_table = buf;
6283 nTables = GET_BE_WORD(tt_kern_table->nTables);
6284 TRACE("version %u, nTables %u\n",
6285 GET_BE_WORD(tt_kern_table->version), nTables);
6287 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6289 for (i = 0; i < nTables; i++)
6291 struct TT_kern_subtable tt_kern_subtable_copy;
6293 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6294 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6295 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6297 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6298 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6299 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6301 /* According to the TrueType specification this is the only format
6302 * that will be properly interpreted by Windows and OS/2
6304 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6306 DWORD new_chunk, old_total = font->total_kern_pairs;
6308 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6309 glyph_to_char, NULL, 0);
6310 font->total_kern_pairs += new_chunk;
6312 if (!font->kern_pairs)
6313 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6314 font->total_kern_pairs * sizeof(*font->kern_pairs));
6315 else
6316 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6317 font->total_kern_pairs * sizeof(*font->kern_pairs));
6319 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6320 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6322 else
6323 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6325 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6328 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6329 HeapFree(GetProcessHeap(), 0, buf);
6331 if (cPairs && kern_pair)
6333 cPairs = min(cPairs, font->total_kern_pairs);
6334 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6335 LeaveCriticalSection( &freetype_cs );
6336 return cPairs;
6338 LeaveCriticalSection( &freetype_cs );
6339 return font->total_kern_pairs;
6342 #else /* HAVE_FREETYPE */
6344 /*************************************************************************/
6346 BOOL WineEngInit(void)
6348 return FALSE;
6350 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6352 return NULL;
6354 BOOL WineEngDestroyFontInstance(HFONT hfont)
6356 return FALSE;
6359 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6361 return 1;
6364 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6365 LPWORD pgi, DWORD flags)
6367 return GDI_ERROR;
6370 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6371 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6372 const MAT2* lpmat)
6374 ERR("called but we don't have FreeType\n");
6375 return GDI_ERROR;
6378 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6380 ERR("called but we don't have FreeType\n");
6381 return FALSE;
6384 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6385 OUTLINETEXTMETRICW *potm)
6387 ERR("called but we don't have FreeType\n");
6388 return 0;
6391 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6392 LPINT buffer)
6394 ERR("called but we don't have FreeType\n");
6395 return FALSE;
6398 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6399 LPABC buffer)
6401 ERR("called but we don't have FreeType\n");
6402 return FALSE;
6405 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6406 LPABC buffer)
6408 ERR("called but we don't have FreeType\n");
6409 return FALSE;
6412 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6413 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6415 ERR("called but we don't have FreeType\n");
6416 return FALSE;
6419 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6420 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6422 ERR("called but we don't have FreeType\n");
6423 return FALSE;
6426 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6427 DWORD cbData)
6429 ERR("called but we don't have FreeType\n");
6430 return GDI_ERROR;
6433 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6435 ERR("called but we don't have FreeType\n");
6436 return 0;
6439 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6441 FIXME(":stub\n");
6442 return 1;
6445 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6447 FIXME(":stub\n");
6448 return TRUE;
6451 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6453 FIXME(":stub\n");
6454 return NULL;
6457 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6459 FIXME(":stub\n");
6460 return DEFAULT_CHARSET;
6463 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6465 return FALSE;
6468 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6470 FIXME("(%p, %p): stub\n", font, glyphset);
6471 return 0;
6474 BOOL WineEngFontIsLinked(GdiFont *font)
6476 return FALSE;
6479 /*************************************************************************
6480 * GetRasterizerCaps (GDI32.@)
6482 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6484 lprs->nSize = sizeof(RASTERIZER_STATUS);
6485 lprs->wFlags = 0;
6486 lprs->nLanguageID = 0;
6487 return TRUE;
6490 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6492 ERR("called but we don't have FreeType\n");
6493 return 0;
6496 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6498 ERR("called but we don't have FreeType\n");
6499 return FALSE;
6502 #endif /* HAVE_FREETYPE */