push cea036dc4aae50c232dc1391dcc459ff0b060bcf
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob0ab4c7a4849dc74426e1ad877fa8d59c006a844e
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 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 #ifdef FT_MULFIX_INLINED
167 #define pFT_MulFix FT_MULFIX_INLINED
168 #else
169 MAKE_FUNCPTR(FT_MulFix);
170 #endif
171 MAKE_FUNCPTR(FT_New_Face);
172 MAKE_FUNCPTR(FT_New_Memory_Face);
173 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
174 MAKE_FUNCPTR(FT_Outline_Transform);
175 MAKE_FUNCPTR(FT_Outline_Translate);
176 MAKE_FUNCPTR(FT_Select_Charmap);
177 MAKE_FUNCPTR(FT_Set_Charmap);
178 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
179 MAKE_FUNCPTR(FT_Vector_Transform);
180 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
181 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
182 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
183 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
184 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
185 #ifdef HAVE_FREETYPE_FTWINFNT_H
186 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
187 #endif
189 #ifdef SONAME_LIBFONTCONFIG
190 #include <fontconfig/fontconfig.h>
191 MAKE_FUNCPTR(FcConfigGetCurrent);
192 MAKE_FUNCPTR(FcFontList);
193 MAKE_FUNCPTR(FcFontSetDestroy);
194 MAKE_FUNCPTR(FcInit);
195 MAKE_FUNCPTR(FcObjectSetAdd);
196 MAKE_FUNCPTR(FcObjectSetCreate);
197 MAKE_FUNCPTR(FcObjectSetDestroy);
198 MAKE_FUNCPTR(FcPatternCreate);
199 MAKE_FUNCPTR(FcPatternDestroy);
200 MAKE_FUNCPTR(FcPatternGetBool);
201 MAKE_FUNCPTR(FcPatternGetString);
202 #endif
204 #undef MAKE_FUNCPTR
206 #ifndef FT_MAKE_TAG
207 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
208 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
209 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
210 #endif
212 #ifndef ft_encoding_none
213 #define FT_ENCODING_NONE ft_encoding_none
214 #endif
215 #ifndef ft_encoding_ms_symbol
216 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
217 #endif
218 #ifndef ft_encoding_unicode
219 #define FT_ENCODING_UNICODE ft_encoding_unicode
220 #endif
221 #ifndef ft_encoding_apple_roman
222 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
223 #endif
225 #ifdef WORDS_BIGENDIAN
226 #define GET_BE_WORD(x) (x)
227 #else
228 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
229 #endif
231 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
232 typedef struct {
233 FT_Short height;
234 FT_Short width;
235 FT_Pos size;
236 FT_Pos x_ppem;
237 FT_Pos y_ppem;
238 FT_Short internal_leading;
239 } Bitmap_Size;
241 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
242 So to let this compile on older versions of FreeType we'll define the
243 new structure here. */
244 typedef struct {
245 FT_Short height, width;
246 FT_Pos size, x_ppem, y_ppem;
247 } My_FT_Bitmap_Size;
249 struct enum_data
251 ENUMLOGFONTEXW elf;
252 NEWTEXTMETRICEXW ntm;
253 DWORD type;
256 typedef struct tagFace {
257 struct list entry;
258 WCHAR *StyleName;
259 char *file;
260 void *font_data_ptr;
261 DWORD font_data_size;
262 FT_Long face_index;
263 FONTSIGNATURE fs;
264 FONTSIGNATURE fs_links;
265 DWORD ntmFlags;
266 FT_Fixed font_version;
267 BOOL scalable;
268 Bitmap_Size size; /* set if face is a bitmap */
269 BOOL external; /* TRUE if we should manually add this font to the registry */
270 struct tagFamily *family;
271 /* Cached data for Enum */
272 struct enum_data *cached_enum_data;
273 } Face;
275 typedef struct tagFamily {
276 struct list entry;
277 const WCHAR *FamilyName;
278 struct list faces;
279 } Family;
281 typedef struct {
282 GLYPHMETRICS gm;
283 INT adv; /* These three hold to widths of the unrotated chars */
284 INT lsb;
285 INT bbx;
286 BOOL init;
287 } GM;
289 typedef struct {
290 FLOAT eM11, eM12;
291 FLOAT eM21, eM22;
292 } FMAT2;
294 typedef struct {
295 DWORD hash;
296 LOGFONTW lf;
297 FMAT2 matrix;
298 BOOL can_use_bitmap;
299 } FONT_DESC;
301 typedef struct tagHFONTLIST {
302 struct list entry;
303 HFONT hfont;
304 } HFONTLIST;
306 typedef struct {
307 struct list entry;
308 Face *face;
309 GdiFont *font;
310 } CHILD_FONT;
312 struct tagGdiFont {
313 struct list entry;
314 GM **gm;
315 DWORD gmsize;
316 struct list hfontlist;
317 OUTLINETEXTMETRICW *potm;
318 DWORD total_kern_pairs;
319 KERNINGPAIR *kern_pairs;
320 struct list child_fonts;
322 /* the following members can be accessed without locking, they are never modified after creation */
323 FT_Face ft_face;
324 struct font_mapping *mapping;
325 LPWSTR name;
326 int charset;
327 int codepage;
328 BOOL fake_italic;
329 BOOL fake_bold;
330 BYTE underline;
331 BYTE strikeout;
332 INT orientation;
333 FONT_DESC font_desc;
334 LONG aveWidth, ppem;
335 double scale_y;
336 SHORT yMax;
337 SHORT yMin;
338 DWORD ntmFlags;
339 FONTSIGNATURE fs;
340 GdiFont *base_font;
341 VOID *GSUB_Table;
342 DWORD cache_num;
345 typedef struct {
346 struct list entry;
347 const WCHAR *font_name;
348 struct list links;
349 } SYSTEM_LINKS;
351 #define GM_BLOCK_SIZE 128
352 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
354 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
355 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
356 #define UNUSED_CACHE_SIZE 10
357 static struct list child_font_list = LIST_INIT(child_font_list);
358 static struct list system_links = LIST_INIT(system_links);
360 static struct list font_subst_list = LIST_INIT(font_subst_list);
362 static struct list font_list = LIST_INIT(font_list);
364 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
365 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
366 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
368 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
369 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s',' ','N','T','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
380 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
381 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
382 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
384 static const WCHAR * const SystemFontValues[4] = {
385 System_Value,
386 OEMFont_Value,
387 FixedSys_Value,
388 NULL
391 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
392 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
394 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
395 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
396 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
397 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
398 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
399 'E','u','r','o','p','e','a','n','\0'};
400 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
401 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
402 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
403 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
404 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
405 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
406 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
407 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
408 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
409 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
410 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
411 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
413 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
414 WesternW, /*00*/
415 Central_EuropeanW,
416 CyrillicW,
417 GreekW,
418 TurkishW,
419 HebrewW,
420 ArabicW,
421 BalticW,
422 VietnameseW, /*08*/
423 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
424 ThaiW,
425 JapaneseW,
426 CHINESE_GB2312W,
427 HangulW,
428 CHINESE_BIG5W,
429 Hangul_Johab_W,
430 NULL, NULL, /*23*/
431 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
432 SymbolW /*31*/
435 typedef struct {
436 WCHAR *name;
437 INT charset;
438 } NameCs;
440 typedef struct tagFontSubst {
441 struct list entry;
442 NameCs from;
443 NameCs to;
444 } FontSubst;
446 struct font_mapping
448 struct list entry;
449 int refcount;
450 dev_t dev;
451 ino_t ino;
452 void *data;
453 size_t size;
456 static struct list mappings_list = LIST_INIT( mappings_list );
458 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
460 static CRITICAL_SECTION freetype_cs;
461 static CRITICAL_SECTION_DEBUG critsect_debug =
463 0, 0, &freetype_cs,
464 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
465 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
467 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
469 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
471 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
472 static BOOL use_default_fallback = FALSE;
474 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
476 /****************************************
477 * Notes on .fon files
479 * The fonts System, FixedSys and Terminal are special. There are typically multiple
480 * versions installed for different resolutions and codepages. Windows stores which one to use
481 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
482 * Key Meaning
483 * FIXEDFON.FON FixedSys
484 * FONTS.FON System
485 * OEMFONT.FON Terminal
486 * LogPixels Current dpi set by the display control panel applet
487 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
488 * also has a LogPixels value that appears to mirror this)
490 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
491 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
492 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
493 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
494 * so that makes sense.
496 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
497 * to be mapped into the registry on Windows 2000 at least).
498 * I have
499 * woafont=app850.fon
500 * ega80woa.fon=ega80850.fon
501 * ega40woa.fon=ega40850.fon
502 * cga80woa.fon=cga80850.fon
503 * cga40woa.fon=cga40850.fon
506 /* These are all structures needed for the GSUB table */
508 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
509 #define TATEGAKI_LOWER_BOUND 0x02F1
511 typedef struct {
512 DWORD version;
513 WORD ScriptList;
514 WORD FeatureList;
515 WORD LookupList;
516 } GSUB_Header;
518 typedef struct {
519 CHAR ScriptTag[4];
520 WORD Script;
521 } GSUB_ScriptRecord;
523 typedef struct {
524 WORD ScriptCount;
525 GSUB_ScriptRecord ScriptRecord[1];
526 } GSUB_ScriptList;
528 typedef struct {
529 CHAR LangSysTag[4];
530 WORD LangSys;
531 } GSUB_LangSysRecord;
533 typedef struct {
534 WORD DefaultLangSys;
535 WORD LangSysCount;
536 GSUB_LangSysRecord LangSysRecord[1];
537 } GSUB_Script;
539 typedef struct {
540 WORD LookupOrder; /* Reserved */
541 WORD ReqFeatureIndex;
542 WORD FeatureCount;
543 WORD FeatureIndex[1];
544 } GSUB_LangSys;
546 typedef struct {
547 CHAR FeatureTag[4];
548 WORD Feature;
549 } GSUB_FeatureRecord;
551 typedef struct {
552 WORD FeatureCount;
553 GSUB_FeatureRecord FeatureRecord[1];
554 } GSUB_FeatureList;
556 typedef struct {
557 WORD FeatureParams; /* Reserved */
558 WORD LookupCount;
559 WORD LookupListIndex[1];
560 } GSUB_Feature;
562 typedef struct {
563 WORD LookupCount;
564 WORD Lookup[1];
565 } GSUB_LookupList;
567 typedef struct {
568 WORD LookupType;
569 WORD LookupFlag;
570 WORD SubTableCount;
571 WORD SubTable[1];
572 } GSUB_LookupTable;
574 typedef struct {
575 WORD CoverageFormat;
576 WORD GlyphCount;
577 WORD GlyphArray[1];
578 } GSUB_CoverageFormat1;
580 typedef struct {
581 WORD Start;
582 WORD End;
583 WORD StartCoverageIndex;
584 } GSUB_RangeRecord;
586 typedef struct {
587 WORD CoverageFormat;
588 WORD RangeCount;
589 GSUB_RangeRecord RangeRecord[1];
590 } GSUB_CoverageFormat2;
592 typedef struct {
593 WORD SubstFormat; /* = 1 */
594 WORD Coverage;
595 WORD DeltaGlyphID;
596 } GSUB_SingleSubstFormat1;
598 typedef struct {
599 WORD SubstFormat; /* = 2 */
600 WORD Coverage;
601 WORD GlyphCount;
602 WORD Substitute[1];
603 }GSUB_SingleSubstFormat2;
605 #ifdef HAVE_CARBON_CARBON_H
606 static char *find_cache_dir(void)
608 FSRef ref;
609 OSErr err;
610 static char cached_path[MAX_PATH];
611 static const char *wine = "/Wine", *fonts = "/Fonts";
613 if(*cached_path) return cached_path;
615 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
616 if(err != noErr)
618 WARN("can't create cached data folder\n");
619 return NULL;
621 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
622 if(err != noErr)
624 WARN("can't create cached data path\n");
625 *cached_path = '\0';
626 return NULL;
628 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
630 ERR("Could not create full path\n");
631 *cached_path = '\0';
632 return NULL;
634 strcat(cached_path, wine);
636 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
638 WARN("Couldn't mkdir %s\n", cached_path);
639 *cached_path = '\0';
640 return NULL;
642 strcat(cached_path, fonts);
643 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
645 WARN("Couldn't mkdir %s\n", cached_path);
646 *cached_path = '\0';
647 return NULL;
649 return cached_path;
652 /******************************************************************
653 * expand_mac_font
655 * Extracts individual TrueType font files from a Mac suitcase font
656 * and saves them into the user's caches directory (see
657 * find_cache_dir()).
658 * Returns a NULL terminated array of filenames.
660 * We do this because they are apps that try to read ttf files
661 * themselves and they don't like Mac suitcase files.
663 static char **expand_mac_font(const char *path)
665 FSRef ref;
666 SInt16 res_ref;
667 OSStatus s;
668 unsigned int idx;
669 const char *out_dir;
670 const char *filename;
671 int output_len;
672 struct {
673 char **array;
674 unsigned int size, max_size;
675 } ret;
677 TRACE("path %s\n", path);
679 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
680 if(s != noErr)
682 WARN("failed to get ref\n");
683 return NULL;
686 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
687 if(s != noErr)
689 TRACE("no data fork, so trying resource fork\n");
690 res_ref = FSOpenResFile(&ref, fsRdPerm);
691 if(res_ref == -1)
693 TRACE("unable to open resource fork\n");
694 return NULL;
698 ret.size = 0;
699 ret.max_size = 10;
700 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
701 if(!ret.array)
703 CloseResFile(res_ref);
704 return NULL;
707 out_dir = find_cache_dir();
709 filename = strrchr(path, '/');
710 if(!filename) filename = path;
711 else filename++;
713 /* output filename has the form out_dir/filename_%04x.ttf */
714 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
716 UseResFile(res_ref);
717 idx = 1;
718 while(1)
720 FamRec *fam_rec;
721 unsigned short *num_faces_ptr, num_faces, face;
722 AsscEntry *assoc;
723 Handle fond;
724 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
726 fond = Get1IndResource(fond_res, idx);
727 if(!fond) break;
728 TRACE("got fond resource %d\n", idx);
729 HLock(fond);
731 fam_rec = *(FamRec**)fond;
732 num_faces_ptr = (unsigned short *)(fam_rec + 1);
733 num_faces = GET_BE_WORD(*num_faces_ptr);
734 num_faces++;
735 assoc = (AsscEntry*)(num_faces_ptr + 1);
736 TRACE("num faces %04x\n", num_faces);
737 for(face = 0; face < num_faces; face++, assoc++)
739 Handle sfnt;
740 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
741 unsigned short size, font_id;
742 char *output;
744 size = GET_BE_WORD(assoc->fontSize);
745 font_id = GET_BE_WORD(assoc->fontID);
746 if(size != 0)
748 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
749 continue;
752 TRACE("trying to load sfnt id %04x\n", font_id);
753 sfnt = GetResource(sfnt_res, font_id);
754 if(!sfnt)
756 TRACE("can't get sfnt resource %04x\n", font_id);
757 continue;
760 output = HeapAlloc(GetProcessHeap(), 0, output_len);
761 if(output)
763 int fd;
765 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
767 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
768 if(fd != -1 || errno == EEXIST)
770 if(fd != -1)
772 unsigned char *sfnt_data;
774 HLock(sfnt);
775 sfnt_data = *(unsigned char**)sfnt;
776 write(fd, sfnt_data, GetHandleSize(sfnt));
777 HUnlock(sfnt);
778 close(fd);
780 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
782 ret.max_size *= 2;
783 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
785 ret.array[ret.size++] = output;
787 else
789 WARN("unable to create %s\n", output);
790 HeapFree(GetProcessHeap(), 0, output);
793 ReleaseResource(sfnt);
795 HUnlock(fond);
796 ReleaseResource(fond);
797 idx++;
799 CloseResFile(res_ref);
801 return ret.array;
804 #endif /* HAVE_CARBON_CARBON_H */
806 static inline BOOL is_win9x(void)
808 return GetVersion() & 0x80000000;
811 This function builds an FT_Fixed from a double. It fails if the absolute
812 value of the float number is greater than 32768.
814 static inline FT_Fixed FT_FixedFromFloat(double f)
816 return f * 0x10000;
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
825 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
829 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
831 Family *family;
832 Face *face;
833 const char *file;
834 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
835 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
837 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
840 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
842 if(face_name && strcmpiW(face_name, family->FamilyName))
843 continue;
844 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
846 if (!face->file)
847 continue;
848 file = strrchr(face->file, '/');
849 if(!file)
850 file = face->file;
851 else
852 file++;
853 if(!strcasecmp(file, file_nameA))
855 HeapFree(GetProcessHeap(), 0, file_nameA);
856 return face;
860 HeapFree(GetProcessHeap(), 0, file_nameA);
861 return NULL;
864 static Family *find_family_from_name(const WCHAR *name)
866 Family *family;
868 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
870 if(!strcmpiW(family->FamilyName, name))
871 return family;
874 return NULL;
877 static void DumpSubstList(void)
879 FontSubst *psub;
881 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
883 if(psub->from.charset != -1 || psub->to.charset != -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
885 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
886 else
887 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
888 debugstr_w(psub->to.name));
890 return;
893 static LPWSTR strdupW(LPCWSTR p)
895 LPWSTR ret;
896 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
897 ret = HeapAlloc(GetProcessHeap(), 0, len);
898 memcpy(ret, p, len);
899 return ret;
902 static LPSTR strdupA(LPCSTR p)
904 LPSTR ret;
905 DWORD len = (strlen(p) + 1);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
907 memcpy(ret, p, len);
908 return ret;
911 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
912 INT from_charset)
914 FontSubst *element;
916 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
918 if(!strcmpiW(element->from.name, from_name) &&
919 (element->from.charset == from_charset ||
920 element->from.charset == -1))
921 return element;
924 return NULL;
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
931 FontSubst *from_exist, *to_exist;
933 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
935 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
937 list_remove(&from_exist->entry);
938 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
939 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
940 HeapFree(GetProcessHeap(), 0, from_exist);
941 from_exist = NULL;
944 if(!from_exist)
946 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
948 if(to_exist)
950 HeapFree(GetProcessHeap(), 0, subst->to.name);
951 subst->to.name = strdupW(to_exist->to.name);
954 list_add_tail(subst_list, &subst->entry);
956 return TRUE;
959 HeapFree(GetProcessHeap(), 0, subst->from.name);
960 HeapFree(GetProcessHeap(), 0, subst->to.name);
961 HeapFree(GetProcessHeap(), 0, subst);
962 return FALSE;
965 static void split_subst_info(NameCs *nc, LPSTR str)
967 CHAR *p = strrchr(str, ',');
968 DWORD len;
970 nc->charset = -1;
971 if(p && *(p+1)) {
972 nc->charset = strtol(p+1, NULL, 10);
973 *p = '\0';
975 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
976 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
980 static void LoadSubstList(void)
982 FontSubst *psub;
983 HKEY hkey;
984 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
985 LPSTR value;
986 LPVOID data;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey) == ERROR_SUCCESS) {
992 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 &valuelen, &datalen, NULL, NULL);
995 valuelen++; /* returned value doesn't include room for '\0' */
996 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
997 data = HeapAlloc(GetProcessHeap(), 0, datalen);
999 dlen = datalen;
1000 vlen = valuelen;
1001 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1002 &dlen) == ERROR_SUCCESS) {
1003 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1005 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1006 split_subst_info(&psub->from, value);
1007 split_subst_info(&psub->to, data);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1012 psub->to.charset == DEFAULT_CHARSET) {
1013 HeapFree(GetProcessHeap(), 0, psub->to.name);
1014 HeapFree(GetProcessHeap(), 0, psub->from.name);
1015 HeapFree(GetProcessHeap(), 0, psub);
1016 } else {
1017 add_font_subst(&font_subst_list, psub, 0);
1019 /* reset dlen and vlen */
1020 dlen = datalen;
1021 vlen = valuelen;
1023 HeapFree(GetProcessHeap(), 0, data);
1024 HeapFree(GetProcessHeap(), 0, value);
1025 RegCloseKey(hkey);
1030 /*****************************************************************
1031 * get_name_table_entry
1033 * Supply the platform, encoding, language and name ids in req
1034 * and if the name exists the function will fill in the string
1035 * and string_len members. The string is owned by FreeType so
1036 * don't free it. Returns TRUE if the name is found else FALSE.
1038 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1040 FT_SfntName name;
1041 FT_UInt num_names, name_index;
1043 if(FT_IS_SFNT(ft_face))
1045 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1047 for(name_index = 0; name_index < num_names; name_index++)
1049 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1051 if((name.platform_id == req->platform_id) &&
1052 (name.encoding_id == req->encoding_id) &&
1053 (name.language_id == req->language_id) &&
1054 (name.name_id == req->name_id))
1056 req->string = name.string;
1057 req->string_len = name.string_len;
1058 return TRUE;
1063 req->string = NULL;
1064 req->string_len = 0;
1065 return FALSE;
1068 static WCHAR *get_familyname(FT_Face ft_face)
1070 WCHAR *family = NULL;
1071 FT_SfntName name;
1073 name.platform_id = TT_PLATFORM_MICROSOFT;
1074 name.encoding_id = TT_MS_ID_UNICODE_CS;
1075 name.language_id = GetUserDefaultLCID();
1076 name.name_id = TT_NAME_ID_FONT_FAMILY;
1078 if(get_name_table_entry(ft_face, &name))
1080 int i;
1082 /* String is not nul terminated and string_len is a byte length. */
1083 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1084 for(i = 0; i < name.string_len / 2; i++)
1086 WORD *tmp = (WORD *)&name.string[i * 2];
1087 family[i] = GET_BE_WORD(*tmp);
1089 family[i] = 0;
1090 TRACE("Got localised name %s\n", debugstr_w(family));
1093 return family;
1097 /*****************************************************************
1098 * load_sfnt_table
1100 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1101 * of FreeType that don't export this function.
1104 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1107 FT_Error err;
1109 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1110 if(pFT_Load_Sfnt_Table)
1112 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1114 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1115 else /* Do it the hard way */
1117 TT_Face tt_face = (TT_Face) ft_face;
1118 SFNT_Interface *sfnt;
1119 if (FT_Version.major==2 && FT_Version.minor==0)
1121 /* 2.0.x */
1122 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1124 else
1126 /* A field was added in the middle of the structure in 2.1.x */
1127 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1129 err = sfnt->load_any(tt_face, table, offset, buf, len);
1131 #else
1132 else
1134 static int msg;
1135 if(!msg)
1137 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1138 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1139 "Please upgrade your freetype library.\n");
1140 msg++;
1142 err = FT_Err_Unimplemented_Feature;
1144 #endif
1145 return err;
1148 static inline int TestStyles(DWORD flags, DWORD styles)
1150 return (flags & styles) == styles;
1153 static int StyleOrdering(Face *face)
1155 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1156 return 3;
1157 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1158 return 2;
1159 if (TestStyles(face->ntmFlags, NTM_BOLD))
1160 return 1;
1161 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1162 return 0;
1164 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1165 debugstr_w(face->family->FamilyName),
1166 debugstr_w(face->StyleName),
1167 face->ntmFlags);
1169 return 9999;
1172 /* Add a style of face to a font family using an ordering of the list such
1173 that regular fonts come before bold and italic, and single styles come
1174 before compound styles. */
1175 static void AddFaceToFamily(Face *face, Family *family)
1177 struct list *entry;
1179 LIST_FOR_EACH( entry, &family->faces )
1181 Face *ent = LIST_ENTRY(entry, Face, entry);
1182 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1184 list_add_before( entry, &face->entry );
1187 #define ADDFONT_EXTERNAL_FONT 0x01
1188 #define ADDFONT_FORCE_BITMAP 0x02
1189 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1191 FT_Face ft_face;
1192 TT_OS2 *pOS2;
1193 TT_Header *pHeader = NULL;
1194 WCHAR *english_family, *localised_family, *StyleW;
1195 DWORD len;
1196 Family *family;
1197 Face *face;
1198 struct list *family_elem_ptr, *face_elem_ptr;
1199 FT_Error err;
1200 FT_Long face_index = 0, num_faces;
1201 #ifdef HAVE_FREETYPE_FTWINFNT_H
1202 FT_WinFNT_HeaderRec winfnt_header;
1203 #endif
1204 int i, bitmap_num, internal_leading;
1205 FONTSIGNATURE fs;
1207 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1208 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1210 #ifdef HAVE_CARBON_CARBON_H
1211 if(file && !fake_family)
1213 char **mac_list = expand_mac_font(file);
1214 if(mac_list)
1216 BOOL had_one = FALSE;
1217 char **cursor;
1218 for(cursor = mac_list; *cursor; cursor++)
1220 had_one = TRUE;
1221 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1222 HeapFree(GetProcessHeap(), 0, *cursor);
1224 HeapFree(GetProcessHeap(), 0, mac_list);
1225 if(had_one)
1226 return 1;
1229 #endif /* HAVE_CARBON_CARBON_H */
1231 do {
1232 char *family_name = fake_family;
1234 if (file)
1236 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1237 err = pFT_New_Face(library, file, face_index, &ft_face);
1238 } else
1240 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1241 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1244 if(err != 0) {
1245 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1246 return 0;
1249 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*/
1250 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1251 pFT_Done_Face(ft_face);
1252 return 0;
1255 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1256 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1257 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1258 pFT_Done_Face(ft_face);
1259 return 0;
1262 if(FT_IS_SFNT(ft_face))
1264 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1265 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1266 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1268 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1269 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1270 pFT_Done_Face(ft_face);
1271 return 0;
1274 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1275 we don't want to load these. */
1276 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1278 FT_ULong len = 0;
1280 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1282 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1283 pFT_Done_Face(ft_face);
1284 return 0;
1289 if(!ft_face->family_name || !ft_face->style_name) {
1290 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1291 pFT_Done_Face(ft_face);
1292 return 0;
1295 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1297 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1298 pFT_Done_Face(ft_face);
1299 return 0;
1302 if (target_family)
1304 localised_family = get_familyname(ft_face);
1305 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1307 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1308 HeapFree(GetProcessHeap(), 0, localised_family);
1309 num_faces = ft_face->num_faces;
1310 pFT_Done_Face(ft_face);
1311 continue;
1313 HeapFree(GetProcessHeap(), 0, localised_family);
1316 if(!family_name)
1317 family_name = ft_face->family_name;
1319 bitmap_num = 0;
1320 do {
1321 My_FT_Bitmap_Size *size = NULL;
1322 FT_ULong tmp_size;
1324 if(!FT_IS_SCALABLE(ft_face))
1325 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1327 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1328 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1329 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1331 localised_family = NULL;
1332 if(!fake_family) {
1333 localised_family = get_familyname(ft_face);
1334 if(localised_family && !strcmpW(localised_family, english_family)) {
1335 HeapFree(GetProcessHeap(), 0, localised_family);
1336 localised_family = NULL;
1340 family = NULL;
1341 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1342 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1343 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1344 break;
1345 family = NULL;
1347 if(!family) {
1348 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1349 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1350 list_init(&family->faces);
1351 list_add_tail(&font_list, &family->entry);
1353 if(localised_family) {
1354 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1355 subst->from.name = strdupW(english_family);
1356 subst->from.charset = -1;
1357 subst->to.name = strdupW(localised_family);
1358 subst->to.charset = -1;
1359 add_font_subst(&font_subst_list, subst, 0);
1362 HeapFree(GetProcessHeap(), 0, localised_family);
1363 HeapFree(GetProcessHeap(), 0, english_family);
1365 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1366 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1367 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1369 internal_leading = 0;
1370 memset(&fs, 0, sizeof(fs));
1372 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1373 if(pOS2) {
1374 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1375 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1376 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1377 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1378 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1379 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1380 if(pOS2->version == 0) {
1381 FT_UInt dummy;
1383 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1384 fs.fsCsb[0] |= FS_LATIN1;
1385 else
1386 fs.fsCsb[0] |= FS_SYMBOL;
1389 #ifdef HAVE_FREETYPE_FTWINFNT_H
1390 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1391 CHARSETINFO csi;
1392 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1393 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1394 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1395 fs = csi.fs;
1396 internal_leading = winfnt_header.internal_leading;
1398 #endif
1400 face_elem_ptr = list_head(&family->faces);
1401 while(face_elem_ptr) {
1402 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1403 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1404 if(!strcmpW(face->StyleName, StyleW) &&
1405 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1406 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1407 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1408 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1410 if(fake_family) {
1411 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1412 HeapFree(GetProcessHeap(), 0, StyleW);
1413 pFT_Done_Face(ft_face);
1414 return 1;
1416 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1417 TRACE("Original font is newer so skipping this one\n");
1418 HeapFree(GetProcessHeap(), 0, StyleW);
1419 pFT_Done_Face(ft_face);
1420 return 1;
1421 } else {
1422 TRACE("Replacing original with this one\n");
1423 list_remove(&face->entry);
1424 HeapFree(GetProcessHeap(), 0, face->file);
1425 HeapFree(GetProcessHeap(), 0, face->StyleName);
1426 HeapFree(GetProcessHeap(), 0, face);
1427 break;
1431 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1432 face->cached_enum_data = NULL;
1433 face->StyleName = StyleW;
1434 if (file)
1436 face->file = strdupA(file);
1437 face->font_data_ptr = NULL;
1438 face->font_data_size = 0;
1440 else
1442 face->file = NULL;
1443 face->font_data_ptr = font_data_ptr;
1444 face->font_data_size = font_data_size;
1446 face->face_index = face_index;
1447 face->ntmFlags = 0;
1448 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1449 face->ntmFlags |= NTM_ITALIC;
1450 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1451 face->ntmFlags |= NTM_BOLD;
1452 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1453 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1454 face->family = family;
1455 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1456 face->fs = fs;
1457 memset(&face->fs_links, 0, sizeof(face->fs_links));
1459 if(FT_IS_SCALABLE(ft_face)) {
1460 memset(&face->size, 0, sizeof(face->size));
1461 face->scalable = TRUE;
1462 } else {
1463 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1464 size->height, size->width, size->size >> 6,
1465 size->x_ppem >> 6, size->y_ppem >> 6);
1466 face->size.height = size->height;
1467 face->size.width = size->width;
1468 face->size.size = size->size;
1469 face->size.x_ppem = size->x_ppem;
1470 face->size.y_ppem = size->y_ppem;
1471 face->size.internal_leading = internal_leading;
1472 face->scalable = FALSE;
1475 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1476 tmp_size = 0;
1477 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1479 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1480 face->ntmFlags |= NTM_PS_OPENTYPE;
1483 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1484 face->fs.fsCsb[0], face->fs.fsCsb[1],
1485 face->fs.fsUsb[0], face->fs.fsUsb[1],
1486 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1489 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1490 for(i = 0; i < ft_face->num_charmaps; i++) {
1491 switch(ft_face->charmaps[i]->encoding) {
1492 case FT_ENCODING_UNICODE:
1493 case FT_ENCODING_APPLE_ROMAN:
1494 face->fs.fsCsb[0] |= FS_LATIN1;
1495 break;
1496 case FT_ENCODING_MS_SYMBOL:
1497 face->fs.fsCsb[0] |= FS_SYMBOL;
1498 break;
1499 default:
1500 break;
1505 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1506 have_installed_roman_font = TRUE;
1508 AddFaceToFamily(face, family);
1510 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1512 num_faces = ft_face->num_faces;
1513 pFT_Done_Face(ft_face);
1514 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1515 debugstr_w(StyleW));
1516 } while(num_faces > ++face_index);
1517 return num_faces;
1520 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1522 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1525 static void DumpFontList(void)
1527 Family *family;
1528 Face *face;
1529 struct list *family_elem_ptr, *face_elem_ptr;
1531 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1532 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1533 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1534 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1535 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1536 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1537 if(!face->scalable)
1538 TRACE(" %d", face->size.height);
1539 TRACE("\n");
1542 return;
1545 /***********************************************************
1546 * The replacement list is a way to map an entire font
1547 * family onto another family. For example adding
1549 * [HKCU\Software\Wine\Fonts\Replacements]
1550 * "Wingdings"="Winedings"
1552 * would enumerate the Winedings font both as Winedings and
1553 * Wingdings. However if a real Wingdings font is present the
1554 * replacement does not take place.
1557 static void LoadReplaceList(void)
1559 HKEY hkey;
1560 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1561 LPWSTR value;
1562 LPVOID data;
1563 Family *family;
1564 Face *face;
1565 struct list *family_elem_ptr, *face_elem_ptr;
1566 CHAR familyA[400];
1568 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1569 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1571 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1572 &valuelen, &datalen, NULL, NULL);
1574 valuelen++; /* returned value doesn't include room for '\0' */
1575 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1576 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1578 dlen = datalen;
1579 vlen = valuelen;
1580 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1581 &dlen) == ERROR_SUCCESS) {
1582 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1583 /* "NewName"="Oldname" */
1584 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1586 /* Find the old family and hence all of the font files
1587 in that family */
1588 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1589 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1590 if(!strcmpiW(family->FamilyName, data)) {
1591 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1592 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1593 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1594 debugstr_w(face->StyleName), familyA);
1595 /* Now add a new entry with the new family name */
1596 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1598 break;
1601 /* reset dlen and vlen */
1602 dlen = datalen;
1603 vlen = valuelen;
1605 HeapFree(GetProcessHeap(), 0, data);
1606 HeapFree(GetProcessHeap(), 0, value);
1607 RegCloseKey(hkey);
1611 /*************************************************************
1612 * init_system_links
1614 static BOOL init_system_links(void)
1616 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1617 'W','i','n','d','o','w','s',' ','N','T','\\',
1618 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1619 'S','y','s','t','e','m','L','i','n','k',0};
1620 HKEY hkey;
1621 BOOL ret = FALSE;
1622 DWORD type, max_val, max_data, val_len, data_len, index;
1623 WCHAR *value, *data;
1624 WCHAR *entry, *next;
1625 SYSTEM_LINKS *font_link, *system_font_link;
1626 CHILD_FONT *child_font;
1627 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1628 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1629 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1630 FONTSIGNATURE fs;
1631 Family *family;
1632 Face *face;
1633 FontSubst *psub;
1635 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1637 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1638 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1639 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1640 val_len = max_val + 1;
1641 data_len = max_data;
1642 index = 0;
1643 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1645 TRACE("%s:\n", debugstr_w(value));
1647 memset(&fs, 0, sizeof(fs));
1648 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1649 psub = get_font_subst(&font_subst_list, value, -1);
1650 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1651 list_init(&font_link->links);
1652 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1654 WCHAR *face_name;
1655 CHILD_FONT *child_font;
1657 TRACE("\t%s\n", debugstr_w(entry));
1659 next = entry + strlenW(entry) + 1;
1661 face_name = strchrW(entry, ',');
1662 if(face_name)
1664 *face_name++ = 0;
1665 while(isspaceW(*face_name))
1666 face_name++;
1668 psub = get_font_subst(&font_subst_list, face_name, -1);
1669 if(psub)
1670 face_name = psub->to.name;
1672 face = find_face_from_filename(entry, face_name);
1673 if(!face)
1675 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1676 continue;
1679 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1680 child_font->face = face;
1681 child_font->font = NULL;
1682 fs.fsCsb[0] |= face->fs.fsCsb[0];
1683 fs.fsCsb[1] |= face->fs.fsCsb[1];
1684 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1685 list_add_tail(&font_link->links, &child_font->entry);
1687 family = find_family_from_name(font_link->font_name);
1688 if(family)
1690 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1692 face->fs_links = fs;
1695 list_add_tail(&system_links, &font_link->entry);
1696 val_len = max_val + 1;
1697 data_len = max_data;
1700 HeapFree(GetProcessHeap(), 0, value);
1701 HeapFree(GetProcessHeap(), 0, data);
1702 RegCloseKey(hkey);
1705 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1706 that Tahoma has */
1708 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1709 system_font_link->font_name = strdupW(System);
1710 list_init(&system_font_link->links);
1712 face = find_face_from_filename(tahoma_ttf, Tahoma);
1713 if(face)
1715 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1716 child_font->face = face;
1717 child_font->font = NULL;
1718 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1719 list_add_tail(&system_font_link->links, &child_font->entry);
1721 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1723 if(!strcmpiW(font_link->font_name, Tahoma))
1725 CHILD_FONT *font_link_entry;
1726 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1728 CHILD_FONT *new_child;
1729 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1730 new_child->face = font_link_entry->face;
1731 new_child->font = NULL;
1732 list_add_tail(&system_font_link->links, &new_child->entry);
1734 break;
1737 list_add_tail(&system_links, &system_font_link->entry);
1738 return ret;
1741 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1743 DIR *dir;
1744 struct dirent *dent;
1745 char path[MAX_PATH];
1747 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1749 dir = opendir(dirname);
1750 if(!dir) {
1751 WARN("Can't open directory %s\n", debugstr_a(dirname));
1752 return FALSE;
1754 while((dent = readdir(dir)) != NULL) {
1755 struct stat statbuf;
1757 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1758 continue;
1760 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1762 sprintf(path, "%s/%s", dirname, dent->d_name);
1764 if(stat(path, &statbuf) == -1)
1766 WARN("Can't stat %s\n", debugstr_a(path));
1767 continue;
1769 if(S_ISDIR(statbuf.st_mode))
1770 ReadFontDir(path, external_fonts);
1771 else
1772 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1774 closedir(dir);
1775 return TRUE;
1778 static void load_fontconfig_fonts(void)
1780 #ifdef SONAME_LIBFONTCONFIG
1781 void *fc_handle = NULL;
1782 FcConfig *config;
1783 FcPattern *pat;
1784 FcObjectSet *os;
1785 FcFontSet *fontset;
1786 int i, len;
1787 char *file;
1788 const char *ext;
1790 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1791 if(!fc_handle) {
1792 TRACE("Wine cannot find the fontconfig library (%s).\n",
1793 SONAME_LIBFONTCONFIG);
1794 return;
1796 #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;}
1797 LOAD_FUNCPTR(FcConfigGetCurrent);
1798 LOAD_FUNCPTR(FcFontList);
1799 LOAD_FUNCPTR(FcFontSetDestroy);
1800 LOAD_FUNCPTR(FcInit);
1801 LOAD_FUNCPTR(FcObjectSetAdd);
1802 LOAD_FUNCPTR(FcObjectSetCreate);
1803 LOAD_FUNCPTR(FcObjectSetDestroy);
1804 LOAD_FUNCPTR(FcPatternCreate);
1805 LOAD_FUNCPTR(FcPatternDestroy);
1806 LOAD_FUNCPTR(FcPatternGetBool);
1807 LOAD_FUNCPTR(FcPatternGetString);
1808 #undef LOAD_FUNCPTR
1810 if(!pFcInit()) return;
1812 config = pFcConfigGetCurrent();
1813 pat = pFcPatternCreate();
1814 os = pFcObjectSetCreate();
1815 pFcObjectSetAdd(os, FC_FILE);
1816 pFcObjectSetAdd(os, FC_SCALABLE);
1817 fontset = pFcFontList(config, pat, os);
1818 if(!fontset) return;
1819 for(i = 0; i < fontset->nfont; i++) {
1820 FcBool scalable;
1822 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1823 continue;
1824 TRACE("fontconfig: %s\n", file);
1826 /* We're just interested in OT/TT fonts for now, so this hack just
1827 picks up the scalable fonts without extensions .pf[ab] to save time
1828 loading every other font */
1830 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1832 TRACE("not scalable\n");
1833 continue;
1836 len = strlen( file );
1837 if(len < 4) continue;
1838 ext = &file[ len - 3 ];
1839 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1840 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1842 pFcFontSetDestroy(fontset);
1843 pFcObjectSetDestroy(os);
1844 pFcPatternDestroy(pat);
1845 sym_not_found:
1846 #endif
1847 return;
1850 static BOOL load_font_from_data_dir(LPCWSTR file)
1852 BOOL ret = FALSE;
1853 const char *data_dir = wine_get_data_dir();
1855 if (!data_dir) data_dir = wine_get_build_dir();
1857 if (data_dir)
1859 INT len;
1860 char *unix_name;
1862 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1864 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1866 strcpy(unix_name, data_dir);
1867 strcat(unix_name, "/fonts/");
1869 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1871 EnterCriticalSection( &freetype_cs );
1872 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1873 LeaveCriticalSection( &freetype_cs );
1874 HeapFree(GetProcessHeap(), 0, unix_name);
1876 return ret;
1879 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1881 static const WCHAR slashW[] = {'\\','\0'};
1882 BOOL ret = FALSE;
1883 WCHAR windowsdir[MAX_PATH];
1884 char *unixname;
1886 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1887 strcatW(windowsdir, fontsW);
1888 strcatW(windowsdir, slashW);
1889 strcatW(windowsdir, file);
1890 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1891 EnterCriticalSection( &freetype_cs );
1892 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1893 LeaveCriticalSection( &freetype_cs );
1894 HeapFree(GetProcessHeap(), 0, unixname);
1896 return ret;
1899 static void load_system_fonts(void)
1901 HKEY hkey;
1902 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1903 const WCHAR * const *value;
1904 DWORD dlen, type;
1905 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1906 char *unixname;
1908 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1909 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1910 strcatW(windowsdir, fontsW);
1911 for(value = SystemFontValues; *value; value++) {
1912 dlen = sizeof(data);
1913 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1914 type == REG_SZ) {
1915 BOOL added = FALSE;
1917 sprintfW(pathW, fmtW, windowsdir, data);
1918 if((unixname = wine_get_unix_file_name(pathW))) {
1919 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1920 HeapFree(GetProcessHeap(), 0, unixname);
1922 if (!added)
1923 load_font_from_data_dir(data);
1926 RegCloseKey(hkey);
1930 /*************************************************************
1932 * This adds registry entries for any externally loaded fonts
1933 * (fonts from fontconfig or FontDirs). It also deletes entries
1934 * of no longer existing fonts.
1937 static void update_reg_entries(void)
1939 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1940 LPWSTR valueW;
1941 DWORD len, len_fam;
1942 Family *family;
1943 Face *face;
1944 struct list *family_elem_ptr, *face_elem_ptr;
1945 WCHAR *file;
1946 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1947 static const WCHAR spaceW[] = {' ', '\0'};
1948 char *path;
1950 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1951 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1952 ERR("Can't create Windows font reg key\n");
1953 goto end;
1956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1957 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1958 ERR("Can't create Windows font reg key\n");
1959 goto end;
1962 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1963 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1964 ERR("Can't create external font reg key\n");
1965 goto end;
1968 /* enumerate the fonts and add external ones to the two keys */
1970 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1971 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1972 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1973 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1974 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1975 if(!face->external) continue;
1976 len = len_fam;
1977 if (!(face->ntmFlags & NTM_REGULAR))
1978 len = len_fam + strlenW(face->StyleName) + 1;
1979 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1980 strcpyW(valueW, family->FamilyName);
1981 if(len != len_fam) {
1982 strcatW(valueW, spaceW);
1983 strcatW(valueW, face->StyleName);
1985 strcatW(valueW, TrueType);
1987 file = wine_get_dos_file_name(face->file);
1988 if(file)
1989 len = strlenW(file) + 1;
1990 else
1992 if((path = strrchr(face->file, '/')) == NULL)
1993 path = face->file;
1994 else
1995 path++;
1996 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1998 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1999 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2001 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2002 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2003 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2005 HeapFree(GetProcessHeap(), 0, file);
2006 HeapFree(GetProcessHeap(), 0, valueW);
2009 end:
2010 if(external_key) RegCloseKey(external_key);
2011 if(win9x_key) RegCloseKey(win9x_key);
2012 if(winnt_key) RegCloseKey(winnt_key);
2013 return;
2016 static void delete_external_font_keys(void)
2018 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2019 DWORD dlen, vlen, datalen, valuelen, i, type;
2020 LPWSTR valueW;
2021 LPVOID data;
2023 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2024 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2025 ERR("Can't create Windows font reg key\n");
2026 goto end;
2029 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2030 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2031 ERR("Can't create Windows font reg key\n");
2032 goto end;
2035 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2036 ERR("Can't create external font reg key\n");
2037 goto end;
2040 /* Delete all external fonts added last time */
2042 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2043 &valuelen, &datalen, NULL, NULL);
2044 valuelen++; /* returned value doesn't include room for '\0' */
2045 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2046 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2048 dlen = datalen * sizeof(WCHAR);
2049 vlen = valuelen;
2050 i = 0;
2051 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2052 &dlen) == ERROR_SUCCESS) {
2054 RegDeleteValueW(winnt_key, valueW);
2055 RegDeleteValueW(win9x_key, valueW);
2056 /* reset dlen and vlen */
2057 dlen = datalen;
2058 vlen = valuelen;
2060 HeapFree(GetProcessHeap(), 0, data);
2061 HeapFree(GetProcessHeap(), 0, valueW);
2063 /* Delete the old external fonts key */
2064 RegCloseKey(external_key);
2065 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2067 end:
2068 if(win9x_key) RegCloseKey(win9x_key);
2069 if(winnt_key) RegCloseKey(winnt_key);
2072 /*************************************************************
2073 * WineEngAddFontResourceEx
2076 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2078 INT ret = 0;
2079 if (ft_handle) /* do it only if we have freetype up and running */
2081 char *unixname;
2083 if(flags)
2084 FIXME("Ignoring flags %x\n", flags);
2086 if((unixname = wine_get_unix_file_name(file)))
2088 EnterCriticalSection( &freetype_cs );
2089 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2090 LeaveCriticalSection( &freetype_cs );
2091 HeapFree(GetProcessHeap(), 0, unixname);
2093 if (!ret && !strchrW(file, '\\')) {
2094 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2095 ret = load_font_from_winfonts_dir(file);
2096 if (!ret) {
2097 /* Try in datadir/fonts (or builddir/fonts),
2098 * needed for Magic the Gathering Online
2100 ret = load_font_from_data_dir(file);
2104 return ret;
2107 /*************************************************************
2108 * WineEngAddFontMemResourceEx
2111 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2113 if (ft_handle) /* do it only if we have freetype up and running */
2115 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2117 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2118 memcpy(pFontCopy, pbFont, cbFont);
2120 EnterCriticalSection( &freetype_cs );
2121 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2122 LeaveCriticalSection( &freetype_cs );
2124 if (*pcFonts == 0)
2126 TRACE("AddFontToList failed\n");
2127 HeapFree(GetProcessHeap(), 0, pFontCopy);
2128 return NULL;
2130 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2131 * For now return something unique but quite random
2133 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2134 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2137 *pcFonts = 0;
2138 return 0;
2141 /*************************************************************
2142 * WineEngRemoveFontResourceEx
2145 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2147 FIXME(":stub\n");
2148 return TRUE;
2151 static const struct nls_update_font_list
2153 UINT ansi_cp, oem_cp;
2154 const char *oem, *fixed, *system;
2155 const char *courier, *serif, *small, *sserif;
2156 /* these are for font substitutes */
2157 const char *shelldlg, *tmsrmn;
2158 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2159 *helv_0, *tmsrmn_0;
2160 const struct subst
2162 const char *from, *to;
2163 } arial_0, courier_new_0, times_new_roman_0;
2164 } nls_update_font_list[] =
2166 /* Latin 1 (United States) */
2167 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2168 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2169 "Tahoma","Times New Roman",
2170 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2171 { 0 }, { 0 }, { 0 }
2173 /* Latin 1 (Multilingual) */
2174 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2175 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2176 "Tahoma","Times New Roman", /* FIXME unverified */
2177 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2178 { 0 }, { 0 }, { 0 }
2180 /* Eastern Europe */
2181 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2182 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2183 "Tahoma","Times New Roman", /* FIXME unverified */
2184 "Fixedsys,238", "System,238",
2185 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2186 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2187 { "Arial CE,0", "Arial,238" },
2188 { "Courier New CE,0", "Courier New,238" },
2189 { "Times New Roman CE,0", "Times New Roman,238" }
2191 /* Cyrillic */
2192 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2193 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2194 "Tahoma","Times New Roman", /* FIXME unverified */
2195 "Fixedsys,204", "System,204",
2196 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2197 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2198 { "Arial Cyr,0", "Arial,204" },
2199 { "Courier New Cyr,0", "Courier New,204" },
2200 { "Times New Roman Cyr,0", "Times New Roman,204" }
2202 /* Greek */
2203 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2204 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,161", "System,161",
2207 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2208 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2209 { "Arial Greek,0", "Arial,161" },
2210 { "Courier New Greek,0", "Courier New,161" },
2211 { "Times New Roman Greek,0", "Times New Roman,161" }
2213 /* Turkish */
2214 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2215 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,162", "System,162",
2218 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2219 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2220 { "Arial Tur,0", "Arial,162" },
2221 { "Courier New Tur,0", "Courier New,162" },
2222 { "Times New Roman Tur,0", "Times New Roman,162" }
2224 /* Hebrew */
2225 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2226 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,177", "System,177",
2229 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2230 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2231 { 0 }, { 0 }, { 0 }
2233 /* Arabic */
2234 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2235 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2236 "Tahoma","Times New Roman", /* FIXME unverified */
2237 "Fixedsys,178", "System,178",
2238 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2239 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2240 { 0 }, { 0 }, { 0 }
2242 /* Baltic */
2243 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2244 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,186", "System,186",
2247 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2248 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2249 { "Arial Baltic,0", "Arial,186" },
2250 { "Courier New Baltic,0", "Courier New,186" },
2251 { "Times New Roman Baltic,0", "Times New Roman,186" }
2253 /* Vietnamese */
2254 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2255 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2258 { 0 }, { 0 }, { 0 }
2260 /* Thai */
2261 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2262 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2265 { 0 }, { 0 }, { 0 }
2267 /* Japanese */
2268 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2269 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2270 "MS UI Gothic","MS Serif",
2271 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2272 { 0 }, { 0 }, { 0 }
2274 /* Chinese Simplified */
2275 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2276 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2277 "Tahoma", "Times New Roman", /* FIXME unverified */
2278 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2279 { 0 }, { 0 }, { 0 }
2281 /* Korean */
2282 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2283 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2284 "Gulim", "Batang",
2285 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2286 { 0 }, { 0 }, { 0 }
2288 /* Chinese Traditional */
2289 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2291 "PMingLiU", "MingLiU",
2292 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2293 { 0 }, { 0 }, { 0 }
2297 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2299 return ( ansi_cp == 932 /* CP932 for Japanese */
2300 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2301 || ansi_cp == 949 /* CP949 for Korean */
2302 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2305 static inline HKEY create_fonts_NT_registry_key(void)
2307 HKEY hkey = 0;
2309 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2310 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2311 return hkey;
2314 static inline HKEY create_fonts_9x_registry_key(void)
2316 HKEY hkey = 0;
2318 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2319 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2320 return hkey;
2323 static inline HKEY create_config_fonts_registry_key(void)
2325 HKEY hkey = 0;
2327 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2328 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2329 return hkey;
2332 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2334 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2335 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2336 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2337 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2340 static void set_value_key(HKEY hkey, const char *name, const char *value)
2342 if (value)
2343 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2344 else if (name)
2345 RegDeleteValueA(hkey, name);
2348 static void update_font_info(void)
2350 char buf[40], cpbuf[40];
2351 DWORD len, type;
2352 HKEY hkey = 0;
2353 UINT i, ansi_cp = 0, oem_cp = 0;
2354 BOOL done = FALSE;
2356 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2357 return;
2359 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2360 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2361 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2362 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2363 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2365 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2366 if (is_dbcs_ansi_cp(ansi_cp))
2367 use_default_fallback = TRUE;
2369 len = sizeof(buf);
2370 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2372 if (!strcmp( buf, cpbuf )) /* already set correctly */
2374 RegCloseKey(hkey);
2375 return;
2377 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2379 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2381 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2382 RegCloseKey(hkey);
2384 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2386 HKEY hkey;
2388 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2389 nls_update_font_list[i].oem_cp == oem_cp)
2391 hkey = create_config_fonts_registry_key();
2392 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2393 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2394 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2395 RegCloseKey(hkey);
2397 hkey = create_fonts_NT_registry_key();
2398 add_font_list(hkey, &nls_update_font_list[i]);
2399 RegCloseKey(hkey);
2401 hkey = create_fonts_9x_registry_key();
2402 add_font_list(hkey, &nls_update_font_list[i]);
2403 RegCloseKey(hkey);
2405 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2407 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2408 strlen(nls_update_font_list[i].shelldlg)+1);
2409 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2410 strlen(nls_update_font_list[i].tmsrmn)+1);
2412 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2413 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2414 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2415 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2416 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2417 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2418 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2419 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2421 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2422 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2423 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2425 RegCloseKey(hkey);
2427 done = TRUE;
2429 else
2431 /* Delete the FontSubstitutes from other locales */
2432 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2434 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2435 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2436 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2437 RegCloseKey(hkey);
2441 if (!done)
2442 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2446 static BOOL init_freetype(void)
2448 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2449 if(!ft_handle) {
2450 WINE_MESSAGE(
2451 "Wine cannot find the FreeType font library. To enable Wine to\n"
2452 "use TrueType fonts please install a version of FreeType greater than\n"
2453 "or equal to 2.0.5.\n"
2454 "http://www.freetype.org\n");
2455 return FALSE;
2458 #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;}
2460 LOAD_FUNCPTR(FT_Vector_Unit)
2461 LOAD_FUNCPTR(FT_Done_Face)
2462 LOAD_FUNCPTR(FT_Get_Char_Index)
2463 LOAD_FUNCPTR(FT_Get_Module)
2464 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2465 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2466 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2467 LOAD_FUNCPTR(FT_Init_FreeType)
2468 LOAD_FUNCPTR(FT_Load_Glyph)
2469 LOAD_FUNCPTR(FT_Matrix_Multiply)
2470 #ifndef FT_MULFIX_INLINED
2471 LOAD_FUNCPTR(FT_MulFix)
2472 #endif
2473 LOAD_FUNCPTR(FT_New_Face)
2474 LOAD_FUNCPTR(FT_New_Memory_Face)
2475 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2476 LOAD_FUNCPTR(FT_Outline_Transform)
2477 LOAD_FUNCPTR(FT_Outline_Translate)
2478 LOAD_FUNCPTR(FT_Select_Charmap)
2479 LOAD_FUNCPTR(FT_Set_Charmap)
2480 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2481 LOAD_FUNCPTR(FT_Vector_Transform)
2483 #undef LOAD_FUNCPTR
2484 /* Don't warn if these ones are missing */
2485 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2486 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2487 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2488 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2489 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2490 #ifdef HAVE_FREETYPE_FTWINFNT_H
2491 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2492 #endif
2493 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2494 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2495 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2496 <= 2.0.3 has FT_Sqrt64 */
2497 goto sym_not_found;
2500 if(pFT_Init_FreeType(&library) != 0) {
2501 ERR("Can't init FreeType library\n");
2502 wine_dlclose(ft_handle, NULL, 0);
2503 ft_handle = NULL;
2504 return FALSE;
2506 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2507 if (pFT_Library_Version)
2508 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2510 if (FT_Version.major<=0)
2512 FT_Version.major=2;
2513 FT_Version.minor=0;
2514 FT_Version.patch=5;
2516 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2517 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2518 ((FT_Version.minor << 8) & 0x00ff00) |
2519 ((FT_Version.patch ) & 0x0000ff);
2521 return TRUE;
2523 sym_not_found:
2524 WINE_MESSAGE(
2525 "Wine cannot find certain functions that it needs inside the FreeType\n"
2526 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2527 "FreeType to at least version 2.0.5.\n"
2528 "http://www.freetype.org\n");
2529 wine_dlclose(ft_handle, NULL, 0);
2530 ft_handle = NULL;
2531 return FALSE;
2534 /*************************************************************
2535 * WineEngInit
2537 * Initialize FreeType library and create a list of available faces
2539 BOOL WineEngInit(void)
2541 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2542 static const WCHAR pathW[] = {'P','a','t','h',0};
2543 HKEY hkey;
2544 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2545 LPVOID data;
2546 WCHAR windowsdir[MAX_PATH];
2547 char *unixname;
2548 HANDLE font_mutex;
2549 const char *data_dir;
2551 TRACE("\n");
2553 /* update locale dependent font info in registry */
2554 update_font_info();
2556 if(!init_freetype()) return FALSE;
2558 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2559 ERR("Failed to create font mutex\n");
2560 return FALSE;
2562 WaitForSingleObject(font_mutex, INFINITE);
2564 delete_external_font_keys();
2566 /* load the system bitmap fonts */
2567 load_system_fonts();
2569 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2570 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2571 strcatW(windowsdir, fontsW);
2572 if((unixname = wine_get_unix_file_name(windowsdir)))
2574 ReadFontDir(unixname, FALSE);
2575 HeapFree(GetProcessHeap(), 0, unixname);
2578 /* load the system truetype fonts */
2579 data_dir = wine_get_data_dir();
2580 if (!data_dir) data_dir = wine_get_build_dir();
2581 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2582 strcpy(unixname, data_dir);
2583 strcat(unixname, "/fonts/");
2584 ReadFontDir(unixname, TRUE);
2585 HeapFree(GetProcessHeap(), 0, unixname);
2588 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2589 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2590 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2591 will skip these. */
2592 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2593 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2594 &hkey) == ERROR_SUCCESS) {
2595 LPWSTR valueW;
2596 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2597 &valuelen, &datalen, NULL, NULL);
2599 valuelen++; /* returned value doesn't include room for '\0' */
2600 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2601 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2602 if (valueW && data)
2604 dlen = datalen * sizeof(WCHAR);
2605 vlen = valuelen;
2606 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2607 &dlen) == ERROR_SUCCESS) {
2608 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2610 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2612 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2613 HeapFree(GetProcessHeap(), 0, unixname);
2616 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2618 WCHAR pathW[MAX_PATH];
2619 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2620 BOOL added = FALSE;
2622 sprintfW(pathW, fmtW, windowsdir, data);
2623 if((unixname = wine_get_unix_file_name(pathW)))
2625 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2626 HeapFree(GetProcessHeap(), 0, unixname);
2628 if (!added)
2629 load_font_from_data_dir(data);
2631 /* reset dlen and vlen */
2632 dlen = datalen;
2633 vlen = valuelen;
2636 HeapFree(GetProcessHeap(), 0, data);
2637 HeapFree(GetProcessHeap(), 0, valueW);
2638 RegCloseKey(hkey);
2641 load_fontconfig_fonts();
2643 /* then look in any directories that we've specified in the config file */
2644 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2645 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2647 DWORD len;
2648 LPWSTR valueW;
2649 LPSTR valueA, ptr;
2651 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2653 len += sizeof(WCHAR);
2654 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2655 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2657 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2658 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2659 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2660 TRACE( "got font path %s\n", debugstr_a(valueA) );
2661 ptr = valueA;
2662 while (ptr)
2664 LPSTR next = strchr( ptr, ':' );
2665 if (next) *next++ = 0;
2666 ReadFontDir( ptr, TRUE );
2667 ptr = next;
2669 HeapFree( GetProcessHeap(), 0, valueA );
2671 HeapFree( GetProcessHeap(), 0, valueW );
2673 RegCloseKey(hkey);
2676 DumpFontList();
2677 LoadSubstList();
2678 DumpSubstList();
2679 LoadReplaceList();
2680 update_reg_entries();
2682 init_system_links();
2684 ReleaseMutex(font_mutex);
2685 return TRUE;
2689 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2691 TT_OS2 *pOS2;
2692 TT_HoriHeader *pHori;
2694 LONG ppem;
2696 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2697 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2699 if(height == 0) height = 16;
2701 /* Calc. height of EM square:
2703 * For +ve lfHeight we have
2704 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2705 * Re-arranging gives:
2706 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2708 * For -ve lfHeight we have
2709 * |lfHeight| = ppem
2710 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2711 * with il = winAscent + winDescent - units_per_em]
2715 if(height > 0) {
2716 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2717 ppem = MulDiv(ft_face->units_per_EM, height,
2718 pHori->Ascender - pHori->Descender);
2719 else
2720 ppem = MulDiv(ft_face->units_per_EM, height,
2721 pOS2->usWinAscent + pOS2->usWinDescent);
2723 else
2724 ppem = -height;
2726 return ppem;
2729 static struct font_mapping *map_font_file( const char *name )
2731 struct font_mapping *mapping;
2732 struct stat st;
2733 int fd;
2735 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2736 if (fstat( fd, &st ) == -1) goto error;
2738 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2740 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2742 mapping->refcount++;
2743 close( fd );
2744 return mapping;
2747 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2748 goto error;
2750 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2751 close( fd );
2753 if (mapping->data == MAP_FAILED)
2755 HeapFree( GetProcessHeap(), 0, mapping );
2756 return NULL;
2758 mapping->refcount = 1;
2759 mapping->dev = st.st_dev;
2760 mapping->ino = st.st_ino;
2761 mapping->size = st.st_size;
2762 list_add_tail( &mappings_list, &mapping->entry );
2763 return mapping;
2765 error:
2766 close( fd );
2767 return NULL;
2770 static void unmap_font_file( struct font_mapping *mapping )
2772 if (!--mapping->refcount)
2774 list_remove( &mapping->entry );
2775 munmap( mapping->data, mapping->size );
2776 HeapFree( GetProcessHeap(), 0, mapping );
2780 static LONG load_VDMX(GdiFont*, LONG);
2782 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2784 FT_Error err;
2785 FT_Face ft_face;
2786 void *data_ptr;
2787 DWORD data_size;
2789 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2791 if (face->file)
2793 if (!(font->mapping = map_font_file( face->file )))
2795 WARN("failed to map %s\n", debugstr_a(face->file));
2796 return 0;
2798 data_ptr = font->mapping->data;
2799 data_size = font->mapping->size;
2801 else
2803 data_ptr = face->font_data_ptr;
2804 data_size = face->font_data_size;
2807 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2808 if(err) {
2809 ERR("FT_New_Face rets %d\n", err);
2810 return 0;
2813 /* set it here, as load_VDMX needs it */
2814 font->ft_face = ft_face;
2816 if(FT_IS_SCALABLE(ft_face)) {
2817 /* load the VDMX table if we have one */
2818 font->ppem = load_VDMX(font, height);
2819 if(font->ppem == 0)
2820 font->ppem = calc_ppem_for_height(ft_face, height);
2821 TRACE("height %d => ppem %d\n", height, font->ppem);
2823 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2824 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2825 } else {
2826 font->ppem = height;
2827 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2828 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2830 return ft_face;
2834 static int get_nearest_charset(Face *face, int *cp)
2836 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2837 a single face with the requested charset. The idea is to check if
2838 the selected font supports the current ANSI codepage, if it does
2839 return the corresponding charset, else return the first charset */
2841 CHARSETINFO csi;
2842 int acp = GetACP(), i;
2843 DWORD fs0;
2845 *cp = acp;
2846 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2847 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2848 return csi.ciCharset;
2850 for(i = 0; i < 32; i++) {
2851 fs0 = 1L << i;
2852 if(face->fs.fsCsb[0] & fs0) {
2853 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2854 *cp = csi.ciACP;
2855 return csi.ciCharset;
2857 else
2858 FIXME("TCI failing on %x\n", fs0);
2862 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2863 face->fs.fsCsb[0], face->file);
2864 *cp = acp;
2865 return DEFAULT_CHARSET;
2868 static GdiFont *alloc_font(void)
2870 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2871 ret->gmsize = 1;
2872 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2873 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2874 ret->potm = NULL;
2875 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2876 ret->total_kern_pairs = (DWORD)-1;
2877 ret->kern_pairs = NULL;
2878 list_init(&ret->hfontlist);
2879 list_init(&ret->child_fonts);
2880 return ret;
2883 static void free_font(GdiFont *font)
2885 struct list *cursor, *cursor2;
2886 int i;
2888 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2890 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2891 struct list *first_hfont;
2892 HFONTLIST *hfontlist;
2893 list_remove(cursor);
2894 if(child->font)
2896 first_hfont = list_head(&child->font->hfontlist);
2897 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2898 DeleteObject(hfontlist->hfont);
2899 HeapFree(GetProcessHeap(), 0, hfontlist);
2900 free_font(child->font);
2902 HeapFree(GetProcessHeap(), 0, child);
2905 if (font->ft_face) pFT_Done_Face(font->ft_face);
2906 if (font->mapping) unmap_font_file( font->mapping );
2907 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2908 HeapFree(GetProcessHeap(), 0, font->potm);
2909 HeapFree(GetProcessHeap(), 0, font->name);
2910 for (i = 0; i < font->gmsize; i++)
2911 HeapFree(GetProcessHeap(),0,font->gm[i]);
2912 HeapFree(GetProcessHeap(), 0, font->gm);
2913 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2914 HeapFree(GetProcessHeap(), 0, font);
2918 /*************************************************************
2919 * load_VDMX
2921 * load the vdmx entry for the specified height
2924 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2925 ( ( (FT_ULong)_x4 << 24 ) | \
2926 ( (FT_ULong)_x3 << 16 ) | \
2927 ( (FT_ULong)_x2 << 8 ) | \
2928 (FT_ULong)_x1 )
2930 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2932 typedef struct {
2933 BYTE bCharSet;
2934 BYTE xRatio;
2935 BYTE yStartRatio;
2936 BYTE yEndRatio;
2937 } Ratios;
2939 typedef struct {
2940 WORD recs;
2941 BYTE startsz;
2942 BYTE endsz;
2943 } VDMX_group;
2945 static LONG load_VDMX(GdiFont *font, LONG height)
2947 WORD hdr[3], tmp;
2948 VDMX_group group;
2949 BYTE devXRatio, devYRatio;
2950 USHORT numRecs, numRatios;
2951 DWORD result, offset = -1;
2952 LONG ppem = 0;
2953 int i;
2955 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2957 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2958 return ppem;
2960 /* FIXME: need the real device aspect ratio */
2961 devXRatio = 1;
2962 devYRatio = 1;
2964 numRecs = GET_BE_WORD(hdr[1]);
2965 numRatios = GET_BE_WORD(hdr[2]);
2967 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2968 for(i = 0; i < numRatios; i++) {
2969 Ratios ratio;
2971 offset = (3 * 2) + (i * sizeof(Ratios));
2972 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2973 offset = -1;
2975 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2977 if((ratio.xRatio == 0 &&
2978 ratio.yStartRatio == 0 &&
2979 ratio.yEndRatio == 0) ||
2980 (devXRatio == ratio.xRatio &&
2981 devYRatio >= ratio.yStartRatio &&
2982 devYRatio <= ratio.yEndRatio))
2984 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2985 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2986 offset = GET_BE_WORD(tmp);
2987 break;
2991 if(offset == -1) {
2992 FIXME("No suitable ratio found\n");
2993 return ppem;
2996 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2997 USHORT recs;
2998 BYTE startsz, endsz;
2999 WORD *vTable;
3001 recs = GET_BE_WORD(group.recs);
3002 startsz = group.startsz;
3003 endsz = group.endsz;
3005 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3007 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3008 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3009 if(result == GDI_ERROR) {
3010 FIXME("Failed to retrieve vTable\n");
3011 goto end;
3014 if(height > 0) {
3015 for(i = 0; i < recs; i++) {
3016 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3017 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3018 ppem = GET_BE_WORD(vTable[i * 3]);
3020 if(yMax + -yMin == height) {
3021 font->yMax = yMax;
3022 font->yMin = yMin;
3023 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3024 break;
3026 if(yMax + -yMin > height) {
3027 if(--i < 0) {
3028 ppem = 0;
3029 goto end; /* failed */
3031 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3032 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3033 ppem = GET_BE_WORD(vTable[i * 3]);
3034 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3035 break;
3038 if(!font->yMax) {
3039 ppem = 0;
3040 TRACE("ppem not found for height %d\n", height);
3042 } else {
3043 ppem = -height;
3044 if(ppem < startsz || ppem > endsz)
3045 goto end;
3047 for(i = 0; i < recs; i++) {
3048 USHORT yPelHeight;
3049 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3051 if(yPelHeight > ppem)
3052 break; /* failed */
3054 if(yPelHeight == ppem) {
3055 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3056 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3057 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3058 break;
3062 end:
3063 HeapFree(GetProcessHeap(), 0, vTable);
3066 return ppem;
3069 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3071 if(font->font_desc.hash != fd->hash) return TRUE;
3072 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3073 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3074 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3075 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3078 static void calc_hash(FONT_DESC *pfd)
3080 DWORD hash = 0, *ptr, two_chars;
3081 WORD *pwc;
3082 unsigned int i;
3084 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3085 hash ^= *ptr;
3086 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3087 hash ^= *ptr;
3088 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3089 two_chars = *ptr;
3090 pwc = (WCHAR *)&two_chars;
3091 if(!*pwc) break;
3092 *pwc = toupperW(*pwc);
3093 pwc++;
3094 *pwc = toupperW(*pwc);
3095 hash ^= two_chars;
3096 if(!*pwc) break;
3098 hash ^= !pfd->can_use_bitmap;
3099 pfd->hash = hash;
3100 return;
3103 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3105 GdiFont *ret;
3106 FONT_DESC fd;
3107 HFONTLIST *hflist;
3108 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3110 fd.lf = *plf;
3111 fd.matrix = *pmat;
3112 fd.can_use_bitmap = can_use_bitmap;
3113 calc_hash(&fd);
3115 /* try the in-use list */
3116 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3117 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3118 if(!fontcmp(ret, &fd)) {
3119 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3120 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3121 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3122 if(hflist->hfont == hfont)
3123 return ret;
3125 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3126 hflist->hfont = hfont;
3127 list_add_head(&ret->hfontlist, &hflist->entry);
3128 return ret;
3132 /* then the unused list */
3133 font_elem_ptr = list_head(&unused_gdi_font_list);
3134 while(font_elem_ptr) {
3135 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3136 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3137 if(!fontcmp(ret, &fd)) {
3138 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3139 assert(list_empty(&ret->hfontlist));
3140 TRACE("Found %p in unused list\n", ret);
3141 list_remove(&ret->entry);
3142 list_add_head(&gdi_font_list, &ret->entry);
3143 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3144 hflist->hfont = hfont;
3145 list_add_head(&ret->hfontlist, &hflist->entry);
3146 return ret;
3149 return NULL;
3152 static void add_to_cache(GdiFont *font)
3154 static DWORD cache_num = 1;
3156 font->cache_num = cache_num++;
3157 list_add_head(&gdi_font_list, &font->entry);
3160 /*************************************************************
3161 * create_child_font_list
3163 static BOOL create_child_font_list(GdiFont *font)
3165 BOOL ret = FALSE;
3166 SYSTEM_LINKS *font_link;
3167 CHILD_FONT *font_link_entry, *new_child;
3169 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3171 if(!strcmpW(font_link->font_name, font->name))
3173 TRACE("found entry in system list\n");
3174 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3176 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3177 new_child->face = font_link_entry->face;
3178 new_child->font = NULL;
3179 list_add_tail(&font->child_fonts, &new_child->entry);
3180 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3182 ret = TRUE;
3183 break;
3187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3188 * Sans Serif. This is how asian windows get default fallbacks for fonts
3190 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3191 font->charset != OEM_CHARSET &&
3192 strcmpW(font->name,szDefaultFallbackLink) != 0)
3193 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3195 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3197 TRACE("found entry in default fallback list\n");
3198 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3200 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3201 new_child->face = font_link_entry->face;
3202 new_child->font = NULL;
3203 list_add_tail(&font->child_fonts, &new_child->entry);
3204 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3206 ret = TRUE;
3207 break;
3211 return ret;
3214 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3216 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3218 if (pFT_Set_Charmap)
3220 FT_Int i;
3221 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3223 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3225 for (i = 0; i < ft_face->num_charmaps; i++)
3227 if (ft_face->charmaps[i]->encoding == encoding)
3229 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3230 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3232 switch (ft_face->charmaps[i]->platform_id)
3234 default:
3235 cmap_def = ft_face->charmaps[i];
3236 break;
3237 case 0: /* Apple Unicode */
3238 cmap0 = ft_face->charmaps[i];
3239 break;
3240 case 1: /* Macintosh */
3241 cmap1 = ft_face->charmaps[i];
3242 break;
3243 case 2: /* ISO */
3244 cmap2 = ft_face->charmaps[i];
3245 break;
3246 case 3: /* Microsoft */
3247 cmap3 = ft_face->charmaps[i];
3248 break;
3252 if (cmap3) /* prefer Microsoft cmap table */
3253 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3254 else if (cmap1)
3255 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3256 else if (cmap2)
3257 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3258 else if (cmap0)
3259 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3260 else if (cmap_def)
3261 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3263 return ft_err == FT_Err_Ok;
3266 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3269 /*************************************************************
3270 * WineEngCreateFontInstance
3273 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3275 GdiFont *ret;
3276 Face *face, *best, *best_bitmap;
3277 Family *family, *last_resort_family;
3278 struct list *family_elem_ptr, *face_elem_ptr;
3279 INT height, width = 0;
3280 unsigned int score = 0, new_score;
3281 signed int diff = 0, newdiff;
3282 BOOL bd, it, can_use_bitmap;
3283 LOGFONTW lf;
3284 CHARSETINFO csi;
3285 HFONTLIST *hflist;
3286 FMAT2 dcmat;
3287 FontSubst *psub = NULL;
3289 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3290 lf.lfWidth = abs(lf.lfWidth);
3292 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3294 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3295 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3296 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3297 lf.lfEscapement);
3299 if(dc->GraphicsMode == GM_ADVANCED)
3300 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3301 else
3303 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3304 font scaling abilities. */
3305 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3306 dcmat.eM21 = dcmat.eM12 = 0;
3309 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3310 dcmat.eM21, dcmat.eM22);
3312 EnterCriticalSection( &freetype_cs );
3314 /* check the cache first */
3315 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3316 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3317 LeaveCriticalSection( &freetype_cs );
3318 return ret;
3321 TRACE("not in cache\n");
3322 if(list_empty(&font_list)) /* No fonts installed */
3324 TRACE("No fonts installed\n");
3325 LeaveCriticalSection( &freetype_cs );
3326 return NULL;
3328 if(!have_installed_roman_font)
3330 TRACE("No roman font installed\n");
3331 LeaveCriticalSection( &freetype_cs );
3332 return NULL;
3335 ret = alloc_font();
3337 ret->font_desc.matrix = dcmat;
3338 ret->font_desc.lf = lf;
3339 ret->font_desc.can_use_bitmap = can_use_bitmap;
3340 calc_hash(&ret->font_desc);
3341 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3342 hflist->hfont = hfont;
3343 list_add_head(&ret->hfontlist, &hflist->entry);
3345 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3346 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3347 original value lfCharSet. Note this is a special case for
3348 Symbol and doesn't happen at least for "Wingdings*" */
3350 if(!strcmpiW(lf.lfFaceName, SymbolW))
3351 lf.lfCharSet = SYMBOL_CHARSET;
3353 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3354 switch(lf.lfCharSet) {
3355 case DEFAULT_CHARSET:
3356 csi.fs.fsCsb[0] = 0;
3357 break;
3358 default:
3359 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3360 csi.fs.fsCsb[0] = 0;
3361 break;
3365 family = NULL;
3366 if(lf.lfFaceName[0] != '\0') {
3367 SYSTEM_LINKS *font_link;
3368 CHILD_FONT *font_link_entry;
3369 LPWSTR FaceName = lf.lfFaceName;
3372 * Check for a leading '@' this signals that the font is being
3373 * requested in tategaki mode (vertical writing substitution) but
3374 * does not affect the fontface that is to be selected.
3376 if (lf.lfFaceName[0]=='@')
3377 FaceName = &lf.lfFaceName[1];
3379 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3381 if(psub) {
3382 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3383 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3384 if (psub->to.charset != -1)
3385 lf.lfCharSet = psub->to.charset;
3388 /* We want a match on name and charset or just name if
3389 charset was DEFAULT_CHARSET. If the latter then
3390 we fixup the returned charset later in get_nearest_charset
3391 where we'll either use the charset of the current ansi codepage
3392 or if that's unavailable the first charset that the font supports.
3394 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3395 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3396 if (!strcmpiW(family->FamilyName, FaceName) ||
3397 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3399 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3400 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3401 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3402 if(face->scalable || can_use_bitmap)
3403 goto found;
3409 * Try check the SystemLink list first for a replacement font.
3410 * We may find good replacements there.
3412 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3414 if(!strcmpiW(font_link->font_name, FaceName))
3416 TRACE("found entry in system list\n");
3417 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3419 face = font_link_entry->face;
3420 family = face->family;
3421 if(csi.fs.fsCsb[0] &
3422 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3424 if(face->scalable || can_use_bitmap)
3425 goto found;
3432 psub = NULL; /* substitution is no more relevant */
3434 /* If requested charset was DEFAULT_CHARSET then try using charset
3435 corresponding to the current ansi codepage */
3436 if (!csi.fs.fsCsb[0])
3438 INT acp = GetACP();
3439 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3440 FIXME("TCI failed on codepage %d\n", acp);
3441 csi.fs.fsCsb[0] = 0;
3442 } else
3443 lf.lfCharSet = csi.ciCharset;
3446 /* Face families are in the top 4 bits of lfPitchAndFamily,
3447 so mask with 0xF0 before testing */
3449 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3450 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3451 strcpyW(lf.lfFaceName, defFixed);
3452 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3453 strcpyW(lf.lfFaceName, defSerif);
3454 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3455 strcpyW(lf.lfFaceName, defSans);
3456 else
3457 strcpyW(lf.lfFaceName, defSans);
3458 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3459 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3460 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3461 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3462 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3463 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3464 if(face->scalable || can_use_bitmap)
3465 goto found;
3470 last_resort_family = NULL;
3471 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3472 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3473 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3474 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3475 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3476 if(face->scalable)
3477 goto found;
3478 if(can_use_bitmap && !last_resort_family)
3479 last_resort_family = family;
3484 if(last_resort_family) {
3485 family = last_resort_family;
3486 csi.fs.fsCsb[0] = 0;
3487 goto found;
3490 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3491 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3492 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3493 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3494 if(face->scalable) {
3495 csi.fs.fsCsb[0] = 0;
3496 WARN("just using first face for now\n");
3497 goto found;
3499 if(can_use_bitmap && !last_resort_family)
3500 last_resort_family = family;
3503 if(!last_resort_family) {
3504 FIXME("can't find a single appropriate font - bailing\n");
3505 free_font(ret);
3506 LeaveCriticalSection( &freetype_cs );
3507 return NULL;
3510 WARN("could only find a bitmap font - this will probably look awful!\n");
3511 family = last_resort_family;
3512 csi.fs.fsCsb[0] = 0;
3514 found:
3515 it = lf.lfItalic ? 1 : 0;
3516 bd = lf.lfWeight > 550 ? 1 : 0;
3518 height = lf.lfHeight;
3520 face = best = best_bitmap = NULL;
3521 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3523 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3525 BOOL italic, bold;
3527 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3528 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3529 new_score = (italic ^ it) + (bold ^ bd);
3530 if(!best || new_score <= score)
3532 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3533 italic, bold, it, bd);
3534 score = new_score;
3535 best = face;
3536 if(best->scalable && score == 0) break;
3537 if(!best->scalable)
3539 if(height > 0)
3540 newdiff = height - (signed int)(best->size.height);
3541 else
3542 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3543 if(!best_bitmap || new_score < score ||
3544 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3546 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3547 diff = newdiff;
3548 best_bitmap = best;
3549 if(score == 0 && diff == 0) break;
3555 if(best)
3556 face = best->scalable ? best : best_bitmap;
3557 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3558 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3560 ret->fs = face->fs;
3562 if(csi.fs.fsCsb[0]) {
3563 ret->charset = lf.lfCharSet;
3564 ret->codepage = csi.ciACP;
3566 else
3567 ret->charset = get_nearest_charset(face, &ret->codepage);
3569 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3570 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3572 ret->aveWidth = height ? lf.lfWidth : 0;
3574 if(!face->scalable) {
3575 /* Windows uses integer scaling factors for bitmap fonts */
3576 INT scale, scaled_height;
3578 /* FIXME: rotation of bitmap fonts is ignored */
3579 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3580 if (ret->aveWidth)
3581 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3582 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3584 if (height != 0) height = diff;
3585 height += face->size.height;
3587 scale = (height + face->size.height - 1) / face->size.height;
3588 scaled_height = scale * face->size.height;
3589 /* XP allows not more than 10% deviation */
3590 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3591 ret->scale_y = scale;
3593 width = face->size.x_ppem >> 6;
3594 height = face->size.y_ppem >> 6;
3596 else
3597 ret->scale_y = 1.0;
3598 TRACE("font scale y: %f\n", ret->scale_y);
3600 ret->ft_face = OpenFontFace(ret, face, width, height);
3602 if (!ret->ft_face)
3604 free_font( ret );
3605 LeaveCriticalSection( &freetype_cs );
3606 return 0;
3609 ret->ntmFlags = face->ntmFlags;
3611 if (ret->charset == SYMBOL_CHARSET &&
3612 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3613 /* No ops */
3615 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3616 /* No ops */
3618 else {
3619 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3622 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3623 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3624 ret->underline = lf.lfUnderline ? 0xff : 0;
3625 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3626 create_child_font_list(ret);
3628 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3630 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3631 if (length != GDI_ERROR)
3633 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3634 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3635 TRACE("Loaded GSUB table of %i bytes\n",length);
3639 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3641 add_to_cache(ret);
3642 LeaveCriticalSection( &freetype_cs );
3643 return ret;
3646 static void dump_gdi_font_list(void)
3648 GdiFont *gdiFont;
3649 struct list *elem_ptr;
3651 TRACE("---------- gdiFont Cache ----------\n");
3652 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3653 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3654 TRACE("gdiFont=%p %s %d\n",
3655 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3658 TRACE("---------- Unused gdiFont Cache ----------\n");
3659 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3660 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3661 TRACE("gdiFont=%p %s %d\n",
3662 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3666 /*************************************************************
3667 * WineEngDestroyFontInstance
3669 * free the gdiFont associated with this handle
3672 BOOL WineEngDestroyFontInstance(HFONT handle)
3674 GdiFont *gdiFont;
3675 HFONTLIST *hflist;
3676 BOOL ret = FALSE;
3677 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3678 int i = 0;
3680 EnterCriticalSection( &freetype_cs );
3682 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3684 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3685 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3686 if(hflist->hfont == handle)
3688 TRACE("removing child font %p from child list\n", gdiFont);
3689 list_remove(&gdiFont->entry);
3690 LeaveCriticalSection( &freetype_cs );
3691 return TRUE;
3695 TRACE("destroying hfont=%p\n", handle);
3696 if(TRACE_ON(font))
3697 dump_gdi_font_list();
3699 font_elem_ptr = list_head(&gdi_font_list);
3700 while(font_elem_ptr) {
3701 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3702 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3704 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3705 while(hfontlist_elem_ptr) {
3706 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3707 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3708 if(hflist->hfont == handle) {
3709 list_remove(&hflist->entry);
3710 HeapFree(GetProcessHeap(), 0, hflist);
3711 ret = TRUE;
3714 if(list_empty(&gdiFont->hfontlist)) {
3715 TRACE("Moving to Unused list\n");
3716 list_remove(&gdiFont->entry);
3717 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3722 font_elem_ptr = list_head(&unused_gdi_font_list);
3723 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3724 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3725 while(font_elem_ptr) {
3726 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3727 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3728 TRACE("freeing %p\n", gdiFont);
3729 list_remove(&gdiFont->entry);
3730 free_font(gdiFont);
3732 LeaveCriticalSection( &freetype_cs );
3733 return ret;
3736 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3737 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3739 GdiFont *font;
3740 LONG width, height;
3742 if (face->cached_enum_data)
3744 TRACE("Cached\n");
3745 *pelf = face->cached_enum_data->elf;
3746 *pntm = face->cached_enum_data->ntm;
3747 *ptype = face->cached_enum_data->type;
3748 return;
3751 font = alloc_font();
3753 if(face->scalable) {
3754 height = -2048; /* 2048 is the most common em size */
3755 width = 0;
3756 } else {
3757 height = face->size.y_ppem >> 6;
3758 width = face->size.x_ppem >> 6;
3760 font->scale_y = 1.0;
3762 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3764 free_font(font);
3765 return;
3768 font->name = strdupW(face->family->FamilyName);
3769 font->ntmFlags = face->ntmFlags;
3771 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3773 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3775 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3777 lstrcpynW(pelf->elfLogFont.lfFaceName,
3778 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3779 LF_FACESIZE);
3780 lstrcpynW(pelf->elfFullName,
3781 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3782 LF_FULLFACESIZE);
3783 lstrcpynW(pelf->elfStyle,
3784 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3785 LF_FACESIZE);
3787 else
3789 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3791 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3793 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3794 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3795 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3798 pntm->ntmTm.ntmFlags = face->ntmFlags;
3799 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3800 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3801 pntm->ntmFontSig = face->fs;
3803 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3805 pelf->elfLogFont.lfEscapement = 0;
3806 pelf->elfLogFont.lfOrientation = 0;
3807 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3808 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3809 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3810 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3811 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3812 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3813 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3814 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3815 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3816 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3817 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3819 *ptype = 0;
3820 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3821 *ptype |= TRUETYPE_FONTTYPE;
3822 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3823 *ptype |= DEVICE_FONTTYPE;
3824 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3825 *ptype |= RASTER_FONTTYPE;
3827 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3828 if (face->cached_enum_data)
3830 face->cached_enum_data->elf = *pelf;
3831 face->cached_enum_data->ntm = *pntm;
3832 face->cached_enum_data->type = *ptype;
3835 free_font(font);
3838 /*************************************************************
3839 * WineEngEnumFonts
3842 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3844 Family *family;
3845 Face *face;
3846 struct list *family_elem_ptr, *face_elem_ptr;
3847 ENUMLOGFONTEXW elf;
3848 NEWTEXTMETRICEXW ntm;
3849 DWORD type;
3850 FONTSIGNATURE fs;
3851 CHARSETINFO csi;
3852 LOGFONTW lf;
3853 int i;
3855 if (!plf)
3857 lf.lfCharSet = DEFAULT_CHARSET;
3858 lf.lfPitchAndFamily = 0;
3859 lf.lfFaceName[0] = 0;
3860 plf = &lf;
3863 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3865 EnterCriticalSection( &freetype_cs );
3866 if(plf->lfFaceName[0]) {
3867 FontSubst *psub;
3868 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3870 if(psub) {
3871 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3872 debugstr_w(psub->to.name));
3873 lf = *plf;
3874 strcpyW(lf.lfFaceName, psub->to.name);
3875 plf = &lf;
3878 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3879 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3880 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3881 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3882 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3883 GetEnumStructs(face, &elf, &ntm, &type);
3884 for(i = 0; i < 32; i++) {
3885 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3886 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3887 strcpyW(elf.elfScript, OEM_DOSW);
3888 i = 32; /* break out of loop */
3889 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3890 continue;
3891 else {
3892 fs.fsCsb[0] = 1L << i;
3893 fs.fsCsb[1] = 0;
3894 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3895 TCI_SRCFONTSIG))
3896 csi.ciCharset = DEFAULT_CHARSET;
3897 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3898 if(csi.ciCharset != DEFAULT_CHARSET) {
3899 elf.elfLogFont.lfCharSet =
3900 ntm.ntmTm.tmCharSet = csi.ciCharset;
3901 if(ElfScriptsW[i])
3902 strcpyW(elf.elfScript, ElfScriptsW[i]);
3903 else
3904 FIXME("Unknown elfscript for bit %d\n", i);
3907 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3908 debugstr_w(elf.elfLogFont.lfFaceName),
3909 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3910 csi.ciCharset, type, debugstr_w(elf.elfScript),
3911 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3912 ntm.ntmTm.ntmFlags);
3913 /* release section before callback (FIXME) */
3914 LeaveCriticalSection( &freetype_cs );
3915 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3916 EnterCriticalSection( &freetype_cs );
3921 } else {
3922 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3923 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3924 face_elem_ptr = list_head(&family->faces);
3925 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3926 GetEnumStructs(face, &elf, &ntm, &type);
3927 for(i = 0; i < 32; i++) {
3928 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3929 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3930 strcpyW(elf.elfScript, OEM_DOSW);
3931 i = 32; /* break out of loop */
3932 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3933 continue;
3934 else {
3935 fs.fsCsb[0] = 1L << i;
3936 fs.fsCsb[1] = 0;
3937 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3938 TCI_SRCFONTSIG))
3939 csi.ciCharset = DEFAULT_CHARSET;
3940 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3941 if(csi.ciCharset != DEFAULT_CHARSET) {
3942 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3943 csi.ciCharset;
3944 if(ElfScriptsW[i])
3945 strcpyW(elf.elfScript, ElfScriptsW[i]);
3946 else
3947 FIXME("Unknown elfscript for bit %d\n", i);
3950 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3951 debugstr_w(elf.elfLogFont.lfFaceName),
3952 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3953 csi.ciCharset, type, debugstr_w(elf.elfScript),
3954 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3955 ntm.ntmTm.ntmFlags);
3956 /* release section before callback (FIXME) */
3957 LeaveCriticalSection( &freetype_cs );
3958 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3959 EnterCriticalSection( &freetype_cs );
3963 LeaveCriticalSection( &freetype_cs );
3964 return 1;
3967 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3969 pt->x.value = vec->x >> 6;
3970 pt->x.fract = (vec->x & 0x3f) << 10;
3971 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3972 pt->y.value = vec->y >> 6;
3973 pt->y.fract = (vec->y & 0x3f) << 10;
3974 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3975 return;
3978 /***************************************************
3979 * According to the MSDN documentation on WideCharToMultiByte,
3980 * certain codepages cannot set the default_used parameter.
3981 * This returns TRUE if the codepage can set that parameter, false else
3982 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3984 static BOOL codepage_sets_default_used(UINT codepage)
3986 switch (codepage)
3988 case CP_UTF7:
3989 case CP_UTF8:
3990 case CP_SYMBOL:
3991 return FALSE;
3992 default:
3993 return TRUE;
3998 * GSUB Table handling functions
4001 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4003 const GSUB_CoverageFormat1* cf1;
4005 cf1 = (GSUB_CoverageFormat1*)table;
4007 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4009 int count = GET_BE_WORD(cf1->GlyphCount);
4010 int i;
4011 TRACE("Coverage Format 1, %i glyphs\n",count);
4012 for (i = 0; i < count; i++)
4013 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4014 return i;
4015 return -1;
4017 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4019 const GSUB_CoverageFormat2* cf2;
4020 int i;
4021 int count;
4022 cf2 = (GSUB_CoverageFormat2*)cf1;
4024 count = GET_BE_WORD(cf2->RangeCount);
4025 TRACE("Coverage Format 2, %i ranges\n",count);
4026 for (i = 0; i < count; i++)
4028 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4029 return -1;
4030 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4031 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4033 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4034 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4037 return -1;
4039 else
4040 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4042 return -1;
4045 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4047 const GSUB_ScriptList *script;
4048 const GSUB_Script *deflt = NULL;
4049 int i;
4050 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4052 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4053 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4055 const GSUB_Script *scr;
4056 int offset;
4058 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4059 scr = (GSUB_Script*)((LPBYTE)script + offset);
4061 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4062 return scr;
4063 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4064 deflt = scr;
4066 return deflt;
4069 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4071 int i;
4072 int offset;
4073 const GSUB_LangSys *Lang;
4075 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4077 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4079 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4080 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4082 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4083 return Lang;
4085 offset = GET_BE_WORD(script->DefaultLangSys);
4086 if (offset)
4088 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4089 return Lang;
4091 return NULL;
4094 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4096 int i;
4097 const GSUB_FeatureList *feature;
4098 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4100 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4101 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4103 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4104 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4106 const GSUB_Feature *feat;
4107 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4108 return feat;
4111 return NULL;
4114 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4116 int i;
4117 int offset;
4118 const GSUB_LookupList *lookup;
4119 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4121 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4122 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4124 const GSUB_LookupTable *look;
4125 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4126 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4127 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4128 if (GET_BE_WORD(look->LookupType) != 1)
4129 FIXME("We only handle SubType 1\n");
4130 else
4132 int j;
4134 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4136 const GSUB_SingleSubstFormat1 *ssf1;
4137 offset = GET_BE_WORD(look->SubTable[j]);
4138 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4139 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4141 int offset = GET_BE_WORD(ssf1->Coverage);
4142 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4143 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4145 TRACE(" Glyph 0x%x ->",glyph);
4146 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4147 TRACE(" 0x%x\n",glyph);
4150 else
4152 const GSUB_SingleSubstFormat2 *ssf2;
4153 INT index;
4154 INT offset;
4156 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4157 offset = GET_BE_WORD(ssf1->Coverage);
4158 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4159 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4160 TRACE(" Coverage index %i\n",index);
4161 if (index != -1)
4163 TRACE(" Glyph is 0x%x ->",glyph);
4164 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4165 TRACE("0x%x\n",glyph);
4171 return glyph;
4174 static const char* get_opentype_script(const GdiFont *font)
4177 * I am not sure if this is the correct way to generate our script tag
4180 switch (font->charset)
4182 case ANSI_CHARSET: return "latn";
4183 case BALTIC_CHARSET: return "latn"; /* ?? */
4184 case CHINESEBIG5_CHARSET: return "hani";
4185 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4186 case GB2312_CHARSET: return "hani";
4187 case GREEK_CHARSET: return "grek";
4188 case HANGUL_CHARSET: return "hang";
4189 case RUSSIAN_CHARSET: return "cyrl";
4190 case SHIFTJIS_CHARSET: return "kana";
4191 case TURKISH_CHARSET: return "latn"; /* ?? */
4192 case VIETNAMESE_CHARSET: return "latn";
4193 case JOHAB_CHARSET: return "latn"; /* ?? */
4194 case ARABIC_CHARSET: return "arab";
4195 case HEBREW_CHARSET: return "hebr";
4196 case THAI_CHARSET: return "thai";
4197 default: return "latn";
4201 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4203 const GSUB_Header *header;
4204 const GSUB_Script *script;
4205 const GSUB_LangSys *language;
4206 const GSUB_Feature *feature;
4208 if (!font->GSUB_Table)
4209 return glyph;
4211 header = font->GSUB_Table;
4213 script = GSUB_get_script_table(header, get_opentype_script(font));
4214 if (!script)
4216 TRACE("Script not found\n");
4217 return glyph;
4219 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4220 if (!language)
4222 TRACE("Language not found\n");
4223 return glyph;
4225 feature = GSUB_get_feature(header, language, "vrt2");
4226 if (!feature)
4227 feature = GSUB_get_feature(header, language, "vert");
4228 if (!feature)
4230 TRACE("vrt2/vert feature not found\n");
4231 return glyph;
4233 return GSUB_apply_feature(header, feature, glyph);
4236 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4238 FT_UInt glyphId;
4240 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4241 WCHAR wc = (WCHAR)glyph;
4242 BOOL default_used;
4243 BOOL *default_used_pointer;
4244 FT_UInt ret;
4245 char buf;
4246 default_used_pointer = NULL;
4247 default_used = FALSE;
4248 if (codepage_sets_default_used(font->codepage))
4249 default_used_pointer = &default_used;
4250 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4251 ret = 0;
4252 else
4253 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4254 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4255 return get_GSUB_vert_glyph(font,ret);
4258 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4259 glyph = glyph + 0xf000;
4260 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4261 return get_GSUB_vert_glyph(font,glyphId);
4264 /*************************************************************
4265 * WineEngGetGlyphIndices
4268 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4269 LPWORD pgi, DWORD flags)
4271 int i;
4272 int default_char = -1;
4274 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4276 for(i = 0; i < count; i++)
4278 pgi[i] = get_glyph_index(font, lpstr[i]);
4279 if (pgi[i] == 0)
4281 if (default_char == -1)
4283 if (FT_IS_SFNT(font->ft_face))
4285 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4286 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4288 else
4290 TEXTMETRICW textm;
4291 WineEngGetTextMetrics(font, &textm);
4292 default_char = textm.tmDefaultChar;
4295 pgi[i] = default_char;
4298 return count;
4301 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4303 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4304 return !memcmp(matrix, &identity, sizeof(FMAT2));
4307 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4309 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4310 return !memcmp(matrix, &identity, sizeof(MAT2));
4313 /*************************************************************
4314 * WineEngGetGlyphOutline
4316 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4317 * except that the first parameter is the HWINEENGFONT of the font in
4318 * question rather than an HDC.
4321 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4322 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4323 const MAT2* lpmat)
4325 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4326 FT_Face ft_face = incoming_font->ft_face;
4327 GdiFont *font = incoming_font;
4328 FT_UInt glyph_index;
4329 DWORD width, height, pitch, needed = 0;
4330 FT_Bitmap ft_bitmap;
4331 FT_Error err;
4332 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4333 FT_Angle angle = 0;
4334 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4335 double widthRatio = 1.0;
4336 FT_Matrix transMat = identityMat;
4337 FT_Matrix transMatUnrotated;
4338 BOOL needsTransform = FALSE;
4339 BOOL tategaki = (font->GSUB_Table != NULL);
4340 UINT original_index;
4342 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4343 buflen, buf, lpmat);
4345 TRACE("font transform %f %f %f %f\n",
4346 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4347 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4349 EnterCriticalSection( &freetype_cs );
4351 if(format & GGO_GLYPH_INDEX) {
4352 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4353 original_index = glyph;
4354 format &= ~GGO_GLYPH_INDEX;
4355 } else {
4356 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4357 ft_face = font->ft_face;
4358 original_index = glyph_index;
4361 /* tategaki never appears to happen to lower glyph index */
4362 if (glyph_index < TATEGAKI_LOWER_BOUND )
4363 tategaki = FALSE;
4365 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4366 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4367 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4368 font->gmsize * sizeof(GM*));
4369 } else {
4370 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4371 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4373 *lpgm = FONT_GM(font,original_index)->gm;
4374 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4375 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4376 lpgm->gmCellIncX, lpgm->gmCellIncY);
4377 LeaveCriticalSection( &freetype_cs );
4378 return 1; /* FIXME */
4382 if (!font->gm[original_index / GM_BLOCK_SIZE])
4383 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4385 /* Scaling factor */
4386 if (font->aveWidth)
4388 TEXTMETRICW tm;
4390 WineEngGetTextMetrics(font, &tm);
4392 widthRatio = (double)font->aveWidth;
4393 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4395 else
4396 widthRatio = font->scale_y;
4398 /* Scaling transform */
4399 if (widthRatio != 1.0 || font->scale_y != 1.0)
4401 FT_Matrix scaleMat;
4402 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4403 scaleMat.xy = 0;
4404 scaleMat.yx = 0;
4405 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4407 pFT_Matrix_Multiply(&scaleMat, &transMat);
4408 needsTransform = TRUE;
4411 /* Slant transform */
4412 if (font->fake_italic) {
4413 FT_Matrix slantMat;
4415 slantMat.xx = (1 << 16);
4416 slantMat.xy = ((1 << 16) >> 2);
4417 slantMat.yx = 0;
4418 slantMat.yy = (1 << 16);
4419 pFT_Matrix_Multiply(&slantMat, &transMat);
4420 needsTransform = TRUE;
4423 /* Rotation transform */
4424 transMatUnrotated = transMat;
4425 if(font->orientation && !tategaki) {
4426 FT_Matrix rotationMat;
4427 FT_Vector vecAngle;
4428 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4429 pFT_Vector_Unit(&vecAngle, angle);
4430 rotationMat.xx = vecAngle.x;
4431 rotationMat.xy = -vecAngle.y;
4432 rotationMat.yx = -rotationMat.xy;
4433 rotationMat.yy = rotationMat.xx;
4435 pFT_Matrix_Multiply(&rotationMat, &transMat);
4436 needsTransform = TRUE;
4439 /* World transform */
4440 if (!is_identity_FMAT2(&font->font_desc.matrix))
4442 FT_Matrix worldMat;
4443 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4444 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4445 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4446 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4447 pFT_Matrix_Multiply(&worldMat, &transMat);
4448 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4449 needsTransform = TRUE;
4452 /* Extra transformation specified by caller */
4453 if (lpmat && !is_identity_MAT2(lpmat))
4455 FT_Matrix extraMat;
4456 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4457 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4458 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4459 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4460 pFT_Matrix_Multiply(&extraMat, &transMat);
4461 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4462 needsTransform = TRUE;
4465 if (needsTransform || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP))
4466 load_flags |= FT_LOAD_NO_BITMAP;
4468 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4470 if(err) {
4471 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4472 LeaveCriticalSection( &freetype_cs );
4473 return GDI_ERROR;
4476 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4477 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4479 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4480 lsb = left >> 6;
4481 bbx = (right - left) >> 6;
4483 if(!needsTransform) {
4484 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4485 bottom = (ft_face->glyph->metrics.horiBearingY -
4486 ft_face->glyph->metrics.height) & -64;
4487 lpgm->gmCellIncX = adv;
4488 lpgm->gmCellIncY = 0;
4489 } else {
4490 INT xc, yc;
4491 FT_Vector vec;
4492 for(xc = 0; xc < 2; xc++) {
4493 for(yc = 0; yc < 2; yc++) {
4494 vec.x = (ft_face->glyph->metrics.horiBearingX +
4495 xc * ft_face->glyph->metrics.width);
4496 vec.y = ft_face->glyph->metrics.horiBearingY -
4497 yc * ft_face->glyph->metrics.height;
4498 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4499 pFT_Vector_Transform(&vec, &transMat);
4500 if(xc == 0 && yc == 0) {
4501 left = right = vec.x;
4502 top = bottom = vec.y;
4503 } else {
4504 if(vec.x < left) left = vec.x;
4505 else if(vec.x > right) right = vec.x;
4506 if(vec.y < bottom) bottom = vec.y;
4507 else if(vec.y > top) top = vec.y;
4511 left = left & -64;
4512 right = (right + 63) & -64;
4513 bottom = bottom & -64;
4514 top = (top + 63) & -64;
4516 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4517 vec.x = ft_face->glyph->metrics.horiAdvance;
4518 vec.y = 0;
4519 pFT_Vector_Transform(&vec, &transMat);
4520 lpgm->gmCellIncX = (vec.x+63) >> 6;
4521 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4523 vec.x = ft_face->glyph->metrics.horiAdvance;
4524 vec.y = 0;
4525 pFT_Vector_Transform(&vec, &transMatUnrotated);
4526 adv = (vec.x+63) >> 6;
4528 lpgm->gmBlackBoxX = (right - left) >> 6;
4529 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4530 lpgm->gmptGlyphOrigin.x = left >> 6;
4531 lpgm->gmptGlyphOrigin.y = top >> 6;
4533 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4534 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4535 lpgm->gmCellIncX, lpgm->gmCellIncY);
4537 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4538 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4540 FONT_GM(font,original_index)->gm = *lpgm;
4541 FONT_GM(font,original_index)->adv = adv;
4542 FONT_GM(font,original_index)->lsb = lsb;
4543 FONT_GM(font,original_index)->bbx = bbx;
4544 FONT_GM(font,original_index)->init = TRUE;
4547 if(format == GGO_METRICS)
4549 LeaveCriticalSection( &freetype_cs );
4550 return 1; /* FIXME */
4553 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4554 TRACE("loaded a bitmap\n");
4555 LeaveCriticalSection( &freetype_cs );
4556 return GDI_ERROR;
4559 switch(format) {
4560 case GGO_BITMAP:
4561 width = lpgm->gmBlackBoxX;
4562 height = lpgm->gmBlackBoxY;
4563 pitch = ((width + 31) >> 5) << 2;
4564 needed = pitch * height;
4566 if(!buf || !buflen) break;
4568 switch(ft_face->glyph->format) {
4569 case ft_glyph_format_bitmap:
4571 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4572 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4573 INT h = ft_face->glyph->bitmap.rows;
4574 while(h--) {
4575 memcpy(dst, src, w);
4576 src += ft_face->glyph->bitmap.pitch;
4577 dst += pitch;
4579 break;
4582 case ft_glyph_format_outline:
4583 ft_bitmap.width = width;
4584 ft_bitmap.rows = height;
4585 ft_bitmap.pitch = pitch;
4586 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4587 ft_bitmap.buffer = buf;
4589 if(needsTransform) {
4590 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4593 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4595 /* Note: FreeType will only set 'black' bits for us. */
4596 memset(buf, 0, needed);
4597 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4598 break;
4600 default:
4601 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4602 LeaveCriticalSection( &freetype_cs );
4603 return GDI_ERROR;
4605 break;
4607 case GGO_GRAY2_BITMAP:
4608 case GGO_GRAY4_BITMAP:
4609 case GGO_GRAY8_BITMAP:
4610 case WINE_GGO_GRAY16_BITMAP:
4612 unsigned int mult, row, col;
4613 BYTE *start, *ptr;
4615 width = lpgm->gmBlackBoxX;
4616 height = lpgm->gmBlackBoxY;
4617 pitch = (width + 3) / 4 * 4;
4618 needed = pitch * height;
4620 if(!buf || !buflen) break;
4622 switch(ft_face->glyph->format) {
4623 case ft_glyph_format_bitmap:
4625 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4626 INT h = ft_face->glyph->bitmap.rows;
4627 INT x;
4628 while(h--) {
4629 for(x = 0; x < pitch; x++)
4631 if(x < ft_face->glyph->bitmap.width)
4632 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4633 else
4634 dst[x] = 0;
4636 src += ft_face->glyph->bitmap.pitch;
4637 dst += pitch;
4639 LeaveCriticalSection( &freetype_cs );
4640 return needed;
4642 case ft_glyph_format_outline:
4644 ft_bitmap.width = width;
4645 ft_bitmap.rows = height;
4646 ft_bitmap.pitch = pitch;
4647 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4648 ft_bitmap.buffer = buf;
4650 if(needsTransform)
4651 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4653 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4655 memset(ft_bitmap.buffer, 0, buflen);
4657 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4659 if(format == GGO_GRAY2_BITMAP)
4660 mult = 4;
4661 else if(format == GGO_GRAY4_BITMAP)
4662 mult = 16;
4663 else if(format == GGO_GRAY8_BITMAP)
4664 mult = 64;
4665 else /* format == WINE_GGO_GRAY16_BITMAP */
4667 LeaveCriticalSection( &freetype_cs );
4668 return needed;
4670 break;
4672 default:
4673 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4674 LeaveCriticalSection( &freetype_cs );
4675 return GDI_ERROR;
4678 start = buf;
4679 for(row = 0; row < height; row++) {
4680 ptr = start;
4681 for(col = 0; col < width; col++, ptr++) {
4682 *ptr = (((int)*ptr) * mult + 128) / 256;
4684 start += pitch;
4686 break;
4689 case GGO_NATIVE:
4691 int contour, point = 0, first_pt;
4692 FT_Outline *outline = &ft_face->glyph->outline;
4693 TTPOLYGONHEADER *pph;
4694 TTPOLYCURVE *ppc;
4695 DWORD pph_start, cpfx, type;
4697 if(buflen == 0) buf = NULL;
4699 if (needsTransform && buf) {
4700 pFT_Outline_Transform(outline, &transMat);
4703 for(contour = 0; contour < outline->n_contours; contour++) {
4704 pph_start = needed;
4705 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4706 first_pt = point;
4707 if(buf) {
4708 pph->dwType = TT_POLYGON_TYPE;
4709 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4711 needed += sizeof(*pph);
4712 point++;
4713 while(point <= outline->contours[contour]) {
4714 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4715 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4716 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4717 cpfx = 0;
4718 do {
4719 if(buf)
4720 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4721 cpfx++;
4722 point++;
4723 } while(point <= outline->contours[contour] &&
4724 (outline->tags[point] & FT_Curve_Tag_On) ==
4725 (outline->tags[point-1] & FT_Curve_Tag_On));
4726 /* At the end of a contour Windows adds the start point, but
4727 only for Beziers */
4728 if(point > outline->contours[contour] &&
4729 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4730 if(buf)
4731 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4732 cpfx++;
4733 } else if(point <= outline->contours[contour] &&
4734 outline->tags[point] & FT_Curve_Tag_On) {
4735 /* add closing pt for bezier */
4736 if(buf)
4737 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4738 cpfx++;
4739 point++;
4741 if(buf) {
4742 ppc->wType = type;
4743 ppc->cpfx = cpfx;
4745 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4747 if(buf)
4748 pph->cb = needed - pph_start;
4750 break;
4752 case GGO_BEZIER:
4754 /* Convert the quadratic Beziers to cubic Beziers.
4755 The parametric eqn for a cubic Bezier is, from PLRM:
4756 r(t) = at^3 + bt^2 + ct + r0
4757 with the control points:
4758 r1 = r0 + c/3
4759 r2 = r1 + (c + b)/3
4760 r3 = r0 + c + b + a
4762 A quadratic Beizer has the form:
4763 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4765 So equating powers of t leads to:
4766 r1 = 2/3 p1 + 1/3 p0
4767 r2 = 2/3 p1 + 1/3 p2
4768 and of course r0 = p0, r3 = p2
4771 int contour, point = 0, first_pt;
4772 FT_Outline *outline = &ft_face->glyph->outline;
4773 TTPOLYGONHEADER *pph;
4774 TTPOLYCURVE *ppc;
4775 DWORD pph_start, cpfx, type;
4776 FT_Vector cubic_control[4];
4777 if(buflen == 0) buf = NULL;
4779 if (needsTransform && buf) {
4780 pFT_Outline_Transform(outline, &transMat);
4783 for(contour = 0; contour < outline->n_contours; contour++) {
4784 pph_start = needed;
4785 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4786 first_pt = point;
4787 if(buf) {
4788 pph->dwType = TT_POLYGON_TYPE;
4789 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4791 needed += sizeof(*pph);
4792 point++;
4793 while(point <= outline->contours[contour]) {
4794 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4795 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4796 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4797 cpfx = 0;
4798 do {
4799 if(type == TT_PRIM_LINE) {
4800 if(buf)
4801 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4802 cpfx++;
4803 point++;
4804 } else {
4805 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4806 so cpfx = 3n */
4808 /* FIXME: Possible optimization in endpoint calculation
4809 if there are two consecutive curves */
4810 cubic_control[0] = outline->points[point-1];
4811 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4812 cubic_control[0].x += outline->points[point].x + 1;
4813 cubic_control[0].y += outline->points[point].y + 1;
4814 cubic_control[0].x >>= 1;
4815 cubic_control[0].y >>= 1;
4817 if(point+1 > outline->contours[contour])
4818 cubic_control[3] = outline->points[first_pt];
4819 else {
4820 cubic_control[3] = outline->points[point+1];
4821 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4822 cubic_control[3].x += outline->points[point].x + 1;
4823 cubic_control[3].y += outline->points[point].y + 1;
4824 cubic_control[3].x >>= 1;
4825 cubic_control[3].y >>= 1;
4828 /* r1 = 1/3 p0 + 2/3 p1
4829 r2 = 1/3 p2 + 2/3 p1 */
4830 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4831 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4832 cubic_control[2] = cubic_control[1];
4833 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4834 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4835 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4836 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4837 if(buf) {
4838 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4839 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4840 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4842 cpfx += 3;
4843 point++;
4845 } while(point <= outline->contours[contour] &&
4846 (outline->tags[point] & FT_Curve_Tag_On) ==
4847 (outline->tags[point-1] & FT_Curve_Tag_On));
4848 /* At the end of a contour Windows adds the start point,
4849 but only for Beziers and we've already done that.
4851 if(point <= outline->contours[contour] &&
4852 outline->tags[point] & FT_Curve_Tag_On) {
4853 /* This is the closing pt of a bezier, but we've already
4854 added it, so just inc point and carry on */
4855 point++;
4857 if(buf) {
4858 ppc->wType = type;
4859 ppc->cpfx = cpfx;
4861 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4863 if(buf)
4864 pph->cb = needed - pph_start;
4866 break;
4869 default:
4870 FIXME("Unsupported format %d\n", format);
4871 LeaveCriticalSection( &freetype_cs );
4872 return GDI_ERROR;
4874 LeaveCriticalSection( &freetype_cs );
4875 return needed;
4878 static BOOL get_bitmap_text_metrics(GdiFont *font)
4880 FT_Face ft_face = font->ft_face;
4881 #ifdef HAVE_FREETYPE_FTWINFNT_H
4882 FT_WinFNT_HeaderRec winfnt_header;
4883 #endif
4884 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4885 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4886 font->potm->otmSize = size;
4888 #define TM font->potm->otmTextMetrics
4889 #ifdef HAVE_FREETYPE_FTWINFNT_H
4890 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4892 TM.tmHeight = winfnt_header.pixel_height;
4893 TM.tmAscent = winfnt_header.ascent;
4894 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4895 TM.tmInternalLeading = winfnt_header.internal_leading;
4896 TM.tmExternalLeading = winfnt_header.external_leading;
4897 TM.tmAveCharWidth = winfnt_header.avg_width;
4898 TM.tmMaxCharWidth = winfnt_header.max_width;
4899 TM.tmWeight = winfnt_header.weight;
4900 TM.tmOverhang = 0;
4901 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4902 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4903 TM.tmFirstChar = winfnt_header.first_char;
4904 TM.tmLastChar = winfnt_header.last_char;
4905 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4906 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4907 TM.tmItalic = winfnt_header.italic;
4908 TM.tmUnderlined = font->underline;
4909 TM.tmStruckOut = font->strikeout;
4910 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4911 TM.tmCharSet = winfnt_header.charset;
4913 else
4914 #endif
4916 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4917 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4918 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4919 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4920 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4921 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4922 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4923 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4924 TM.tmOverhang = 0;
4925 TM.tmDigitizedAspectX = 96; /* FIXME */
4926 TM.tmDigitizedAspectY = 96; /* FIXME */
4927 TM.tmFirstChar = 1;
4928 TM.tmLastChar = 255;
4929 TM.tmDefaultChar = 32;
4930 TM.tmBreakChar = 32;
4931 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4932 TM.tmUnderlined = font->underline;
4933 TM.tmStruckOut = font->strikeout;
4934 /* NB inverted meaning of TMPF_FIXED_PITCH */
4935 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4936 TM.tmCharSet = font->charset;
4938 #undef TM
4940 return TRUE;
4944 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4946 double scale_x, scale_y;
4948 if (font->aveWidth)
4950 scale_x = (double)font->aveWidth;
4951 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4953 else
4954 scale_x = font->scale_y;
4956 scale_x *= fabs(font->font_desc.matrix.eM11);
4957 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4959 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4960 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4962 SCALE_Y(ptm->tmHeight);
4963 SCALE_Y(ptm->tmAscent);
4964 SCALE_Y(ptm->tmDescent);
4965 SCALE_Y(ptm->tmInternalLeading);
4966 SCALE_Y(ptm->tmExternalLeading);
4967 SCALE_Y(ptm->tmOverhang);
4969 SCALE_X(ptm->tmAveCharWidth);
4970 SCALE_X(ptm->tmMaxCharWidth);
4972 #undef SCALE_X
4973 #undef SCALE_Y
4976 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4978 double scale_x, scale_y;
4980 if (font->aveWidth)
4982 scale_x = (double)font->aveWidth;
4983 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4985 else
4986 scale_x = font->scale_y;
4988 scale_x *= fabs(font->font_desc.matrix.eM11);
4989 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4991 scale_font_metrics(font, &potm->otmTextMetrics);
4993 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4994 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4996 SCALE_Y(potm->otmAscent);
4997 SCALE_Y(potm->otmDescent);
4998 SCALE_Y(potm->otmLineGap);
4999 SCALE_Y(potm->otmsCapEmHeight);
5000 SCALE_Y(potm->otmsXHeight);
5001 SCALE_Y(potm->otmrcFontBox.top);
5002 SCALE_Y(potm->otmrcFontBox.bottom);
5003 SCALE_X(potm->otmrcFontBox.left);
5004 SCALE_X(potm->otmrcFontBox.right);
5005 SCALE_Y(potm->otmMacAscent);
5006 SCALE_Y(potm->otmMacDescent);
5007 SCALE_Y(potm->otmMacLineGap);
5008 SCALE_X(potm->otmptSubscriptSize.x);
5009 SCALE_Y(potm->otmptSubscriptSize.y);
5010 SCALE_X(potm->otmptSubscriptOffset.x);
5011 SCALE_Y(potm->otmptSubscriptOffset.y);
5012 SCALE_X(potm->otmptSuperscriptSize.x);
5013 SCALE_Y(potm->otmptSuperscriptSize.y);
5014 SCALE_X(potm->otmptSuperscriptOffset.x);
5015 SCALE_Y(potm->otmptSuperscriptOffset.y);
5016 SCALE_Y(potm->otmsStrikeoutSize);
5017 SCALE_Y(potm->otmsStrikeoutPosition);
5018 SCALE_Y(potm->otmsUnderscoreSize);
5019 SCALE_Y(potm->otmsUnderscorePosition);
5021 #undef SCALE_X
5022 #undef SCALE_Y
5025 /*************************************************************
5026 * WineEngGetTextMetrics
5029 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5031 EnterCriticalSection( &freetype_cs );
5032 if(!font->potm) {
5033 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5034 if(!get_bitmap_text_metrics(font))
5036 LeaveCriticalSection( &freetype_cs );
5037 return FALSE;
5040 if(!font->potm)
5042 LeaveCriticalSection( &freetype_cs );
5043 return FALSE;
5045 *ptm = font->potm->otmTextMetrics;
5046 scale_font_metrics(font, ptm);
5047 LeaveCriticalSection( &freetype_cs );
5048 return TRUE;
5052 /*************************************************************
5053 * WineEngGetOutlineTextMetrics
5056 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5057 OUTLINETEXTMETRICW *potm)
5059 FT_Face ft_face = font->ft_face;
5060 UINT needed, lenfam, lensty, ret;
5061 TT_OS2 *pOS2;
5062 TT_HoriHeader *pHori;
5063 TT_Postscript *pPost;
5064 FT_Fixed x_scale, y_scale;
5065 WCHAR *family_nameW, *style_nameW;
5066 static const WCHAR spaceW[] = {' ', '\0'};
5067 char *cp;
5068 INT ascent, descent;
5070 TRACE("font=%p\n", font);
5072 if(!FT_IS_SCALABLE(ft_face))
5073 return 0;
5075 EnterCriticalSection( &freetype_cs );
5077 if(font->potm) {
5078 if(cbSize >= font->potm->otmSize)
5080 memcpy(potm, font->potm, font->potm->otmSize);
5081 scale_outline_font_metrics(font, potm);
5083 LeaveCriticalSection( &freetype_cs );
5084 return font->potm->otmSize;
5088 needed = sizeof(*potm);
5090 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5091 family_nameW = strdupW(font->name);
5093 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5094 * sizeof(WCHAR);
5095 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5096 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5097 style_nameW, lensty/sizeof(WCHAR));
5099 /* These names should be read from the TT name table */
5101 /* length of otmpFamilyName */
5102 needed += lenfam;
5104 /* length of otmpFaceName */
5105 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5106 needed += lenfam; /* just the family name */
5107 } else {
5108 needed += lenfam + lensty; /* family + " " + style */
5111 /* length of otmpStyleName */
5112 needed += lensty;
5114 /* length of otmpFullName */
5115 needed += lenfam + lensty;
5118 x_scale = ft_face->size->metrics.x_scale;
5119 y_scale = ft_face->size->metrics.y_scale;
5121 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5122 if(!pOS2) {
5123 FIXME("Can't find OS/2 table - not TT font?\n");
5124 ret = 0;
5125 goto end;
5128 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5129 if(!pHori) {
5130 FIXME("Can't find HHEA table - not TT font?\n");
5131 ret = 0;
5132 goto end;
5135 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5137 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",
5138 pOS2->usWinAscent, pOS2->usWinDescent,
5139 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5140 ft_face->ascender, ft_face->descender, ft_face->height,
5141 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5142 ft_face->bbox.yMax, ft_face->bbox.yMin);
5144 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5145 font->potm->otmSize = needed;
5147 #define TM font->potm->otmTextMetrics
5149 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5150 ascent = pHori->Ascender;
5151 descent = -pHori->Descender;
5152 } else {
5153 ascent = pOS2->usWinAscent;
5154 descent = pOS2->usWinDescent;
5157 if(font->yMax) {
5158 TM.tmAscent = font->yMax;
5159 TM.tmDescent = -font->yMin;
5160 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5161 } else {
5162 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5163 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5164 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5165 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5168 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5170 /* MSDN says:
5171 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5173 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5174 ((ascent + descent) -
5175 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5177 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5178 if (TM.tmAveCharWidth == 0) {
5179 TM.tmAveCharWidth = 1;
5181 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5182 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5183 TM.tmOverhang = 0;
5184 TM.tmDigitizedAspectX = 300;
5185 TM.tmDigitizedAspectY = 300;
5186 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5187 * symbol range to 0 - f0ff
5189 if (font->charset == SYMBOL_CHARSET)
5191 TM.tmFirstChar = 0;
5192 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5194 else
5196 TM.tmFirstChar = pOS2->usFirstCharIndex;
5197 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5199 TM.tmLastChar = pOS2->usLastCharIndex;
5200 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5201 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5202 TM.tmUnderlined = font->underline;
5203 TM.tmStruckOut = font->strikeout;
5205 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5206 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5207 (pOS2->version == 0xFFFFU ||
5208 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5209 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5210 else
5211 TM.tmPitchAndFamily = 0;
5213 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5214 case PAN_FAMILY_SCRIPT:
5215 TM.tmPitchAndFamily |= FF_SCRIPT;
5216 break;
5217 case PAN_FAMILY_DECORATIVE:
5218 case PAN_FAMILY_PICTORIAL:
5219 TM.tmPitchAndFamily |= FF_DECORATIVE;
5220 break;
5221 case PAN_FAMILY_TEXT_DISPLAY:
5222 if(TM.tmPitchAndFamily == 0) /* fixed */
5223 TM.tmPitchAndFamily = FF_MODERN;
5224 else {
5225 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5226 case PAN_SERIF_NORMAL_SANS:
5227 case PAN_SERIF_OBTUSE_SANS:
5228 case PAN_SERIF_PERP_SANS:
5229 TM.tmPitchAndFamily |= FF_SWISS;
5230 break;
5231 default:
5232 TM.tmPitchAndFamily |= FF_ROMAN;
5235 break;
5236 default:
5237 TM.tmPitchAndFamily |= FF_DONTCARE;
5240 if(FT_IS_SCALABLE(ft_face))
5241 TM.tmPitchAndFamily |= TMPF_VECTOR;
5243 if(FT_IS_SFNT(ft_face))
5245 if (font->ntmFlags & NTM_PS_OPENTYPE)
5246 TM.tmPitchAndFamily |= TMPF_DEVICE;
5247 else
5248 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5251 TM.tmCharSet = font->charset;
5253 font->potm->otmFiller = 0;
5254 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5255 font->potm->otmfsSelection = pOS2->fsSelection;
5256 font->potm->otmfsType = pOS2->fsType;
5257 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5258 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5259 font->potm->otmItalicAngle = 0; /* POST table */
5260 font->potm->otmEMSquare = ft_face->units_per_EM;
5261 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5262 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5263 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5264 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5265 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5266 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5267 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5268 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5269 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5270 font->potm->otmMacAscent = TM.tmAscent;
5271 font->potm->otmMacDescent = -TM.tmDescent;
5272 font->potm->otmMacLineGap = font->potm->otmLineGap;
5273 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5274 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5275 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5276 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5277 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5278 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5279 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5280 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5281 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5282 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5283 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5284 if(!pPost) {
5285 font->potm->otmsUnderscoreSize = 0;
5286 font->potm->otmsUnderscorePosition = 0;
5287 } else {
5288 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5289 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5291 #undef TM
5293 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5294 cp = (char*)font->potm + sizeof(*font->potm);
5295 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5296 strcpyW((WCHAR*)cp, family_nameW);
5297 cp += lenfam;
5298 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5299 strcpyW((WCHAR*)cp, style_nameW);
5300 cp += lensty;
5301 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5302 strcpyW((WCHAR*)cp, family_nameW);
5303 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5304 strcatW((WCHAR*)cp, spaceW);
5305 strcatW((WCHAR*)cp, style_nameW);
5306 cp += lenfam + lensty;
5307 } else
5308 cp += lenfam;
5309 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5310 strcpyW((WCHAR*)cp, family_nameW);
5311 strcatW((WCHAR*)cp, spaceW);
5312 strcatW((WCHAR*)cp, style_nameW);
5313 ret = needed;
5315 if(potm && needed <= cbSize)
5317 memcpy(potm, font->potm, font->potm->otmSize);
5318 scale_outline_font_metrics(font, potm);
5321 end:
5322 HeapFree(GetProcessHeap(), 0, style_nameW);
5323 HeapFree(GetProcessHeap(), 0, family_nameW);
5325 LeaveCriticalSection( &freetype_cs );
5326 return ret;
5329 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5331 HFONTLIST *hfontlist;
5332 child->font = alloc_font();
5333 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5334 if(!child->font->ft_face)
5336 free_font(child->font);
5337 child->font = NULL;
5338 return FALSE;
5341 child->font->ntmFlags = child->face->ntmFlags;
5342 child->font->orientation = font->orientation;
5343 child->font->scale_y = font->scale_y;
5344 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5345 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5346 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5347 child->font->base_font = font;
5348 list_add_head(&child_font_list, &child->font->entry);
5349 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5350 return TRUE;
5353 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5355 FT_UInt g;
5356 CHILD_FONT *child_font;
5358 if(font->base_font)
5359 font = font->base_font;
5361 *linked_font = font;
5363 if((*glyph = get_glyph_index(font, c)))
5364 return TRUE;
5366 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5368 if(!child_font->font)
5369 if(!load_child_font(font, child_font))
5370 continue;
5372 if(!child_font->font->ft_face)
5373 continue;
5374 g = get_glyph_index(child_font->font, c);
5375 if(g)
5377 *glyph = g;
5378 *linked_font = child_font->font;
5379 return TRUE;
5382 return FALSE;
5385 /*************************************************************
5386 * WineEngGetCharWidth
5389 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5390 LPINT buffer)
5392 UINT c;
5393 GLYPHMETRICS gm;
5394 FT_UInt glyph_index;
5395 GdiFont *linked_font;
5397 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5399 EnterCriticalSection( &freetype_cs );
5400 for(c = firstChar; c <= lastChar; c++) {
5401 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5402 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5403 &gm, 0, NULL, NULL);
5404 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5406 LeaveCriticalSection( &freetype_cs );
5407 return TRUE;
5410 /*************************************************************
5411 * WineEngGetCharABCWidths
5414 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5415 LPABC buffer)
5417 UINT c;
5418 GLYPHMETRICS gm;
5419 FT_UInt glyph_index;
5420 GdiFont *linked_font;
5422 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5424 if(!FT_IS_SCALABLE(font->ft_face))
5425 return FALSE;
5427 EnterCriticalSection( &freetype_cs );
5429 for(c = firstChar; c <= lastChar; c++) {
5430 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5431 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5432 &gm, 0, NULL, NULL);
5433 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5434 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5435 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5436 FONT_GM(linked_font,glyph_index)->bbx;
5438 LeaveCriticalSection( &freetype_cs );
5439 return TRUE;
5442 /*************************************************************
5443 * WineEngGetCharABCWidthsI
5446 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5447 LPABC buffer)
5449 UINT c;
5450 GLYPHMETRICS gm;
5451 FT_UInt glyph_index;
5452 GdiFont *linked_font;
5454 if(!FT_HAS_HORIZONTAL(font->ft_face))
5455 return FALSE;
5457 EnterCriticalSection( &freetype_cs );
5459 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5460 if (!pgi)
5461 for(c = firstChar; c < firstChar+count; c++) {
5462 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5463 &gm, 0, NULL, NULL);
5464 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5465 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5466 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5467 - FONT_GM(linked_font,c)->bbx;
5469 else
5470 for(c = 0; c < count; c++) {
5471 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5472 &gm, 0, NULL, NULL);
5473 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5474 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5475 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5476 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5479 LeaveCriticalSection( &freetype_cs );
5480 return TRUE;
5483 /*************************************************************
5484 * WineEngGetTextExtentExPoint
5487 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5488 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5490 INT idx;
5491 INT nfit = 0, ext;
5492 GLYPHMETRICS gm;
5493 TEXTMETRICW tm;
5494 FT_UInt glyph_index;
5495 GdiFont *linked_font;
5497 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5498 max_ext, size);
5500 EnterCriticalSection( &freetype_cs );
5502 size->cx = 0;
5503 WineEngGetTextMetrics(font, &tm);
5504 size->cy = tm.tmHeight;
5506 for(idx = 0; idx < count; idx++) {
5507 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5508 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5509 &gm, 0, NULL, NULL);
5510 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5511 ext = size->cx;
5512 if (! pnfit || ext <= max_ext) {
5513 ++nfit;
5514 if (dxs)
5515 dxs[idx] = ext;
5519 if (pnfit)
5520 *pnfit = nfit;
5522 LeaveCriticalSection( &freetype_cs );
5523 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5524 return TRUE;
5527 /*************************************************************
5528 * WineEngGetTextExtentExPointI
5531 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5532 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5534 INT idx;
5535 INT nfit = 0, ext;
5536 GLYPHMETRICS gm;
5537 TEXTMETRICW tm;
5539 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5541 EnterCriticalSection( &freetype_cs );
5543 size->cx = 0;
5544 WineEngGetTextMetrics(font, &tm);
5545 size->cy = tm.tmHeight;
5547 for(idx = 0; idx < count; idx++) {
5548 WineEngGetGlyphOutline(font, indices[idx],
5549 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5550 NULL);
5551 size->cx += FONT_GM(font,indices[idx])->adv;
5552 ext = size->cx;
5553 if (! pnfit || ext <= max_ext) {
5554 ++nfit;
5555 if (dxs)
5556 dxs[idx] = ext;
5560 if (pnfit)
5561 *pnfit = nfit;
5563 LeaveCriticalSection( &freetype_cs );
5564 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5565 return TRUE;
5568 /*************************************************************
5569 * WineEngGetFontData
5572 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5573 DWORD cbData)
5575 FT_Face ft_face = font->ft_face;
5576 FT_ULong len;
5577 FT_Error err;
5579 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5580 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5581 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5583 if(!FT_IS_SFNT(ft_face))
5584 return GDI_ERROR;
5586 if(!buf || !cbData)
5587 len = 0;
5588 else
5589 len = cbData;
5591 if(table) { /* MS tags differ in endianness from FT ones */
5592 table = table >> 24 | table << 24 |
5593 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5596 /* make sure value of len is the value freetype says it needs */
5597 if(buf && len)
5599 FT_ULong needed = 0;
5600 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5601 if( !err && needed < len) len = needed;
5603 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5605 if(err) {
5606 TRACE("Can't find table %c%c%c%c\n",
5607 /* bytes were reversed */
5608 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5609 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5610 return GDI_ERROR;
5612 return len;
5615 /*************************************************************
5616 * WineEngGetTextFace
5619 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5621 INT n = strlenW(font->name) + 1;
5622 if(str) {
5623 lstrcpynW(str, font->name, count);
5624 return min(count, n);
5625 } else
5626 return n;
5629 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5631 if (fs) *fs = font->fs;
5632 return font->charset;
5635 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5637 GdiFont *font = dc->gdiFont, *linked_font;
5638 struct list *first_hfont;
5639 BOOL ret;
5641 EnterCriticalSection( &freetype_cs );
5642 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5643 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5644 if(font == linked_font)
5645 *new_hfont = dc->hFont;
5646 else
5648 first_hfont = list_head(&linked_font->hfontlist);
5649 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5651 LeaveCriticalSection( &freetype_cs );
5652 return ret;
5655 /* Retrieve a list of supported Unicode ranges for a given font.
5656 * Can be called with NULL gs to calculate the buffer size. Returns
5657 * the number of ranges found.
5659 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5661 DWORD num_ranges = 0;
5663 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5665 FT_UInt glyph_code;
5666 FT_ULong char_code, char_code_prev;
5668 glyph_code = 0;
5669 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5671 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5672 face->num_glyphs, glyph_code, char_code);
5674 if (!glyph_code) return 0;
5676 if (gs)
5678 gs->ranges[0].wcLow = (USHORT)char_code;
5679 gs->ranges[0].cGlyphs = 0;
5680 gs->cGlyphsSupported = 0;
5683 num_ranges = 1;
5684 while (glyph_code)
5686 if (char_code < char_code_prev)
5688 ERR("expected increasing char code from FT_Get_Next_Char\n");
5689 return 0;
5691 if (char_code - char_code_prev > 1)
5693 num_ranges++;
5694 if (gs)
5696 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5697 gs->ranges[num_ranges - 1].cGlyphs = 1;
5698 gs->cGlyphsSupported++;
5701 else if (gs)
5703 gs->ranges[num_ranges - 1].cGlyphs++;
5704 gs->cGlyphsSupported++;
5706 char_code_prev = char_code;
5707 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5710 else
5711 FIXME("encoding %u not supported\n", face->charmap->encoding);
5713 return num_ranges;
5716 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5718 DWORD size = 0;
5719 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5721 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5722 if (glyphset)
5724 glyphset->cbThis = size;
5725 glyphset->cRanges = num_ranges;
5727 return size;
5730 /*************************************************************
5731 * FontIsLinked
5733 BOOL WineEngFontIsLinked(GdiFont *font)
5735 BOOL ret;
5736 EnterCriticalSection( &freetype_cs );
5737 ret = !list_empty(&font->child_fonts);
5738 LeaveCriticalSection( &freetype_cs );
5739 return ret;
5742 static BOOL is_hinting_enabled(void)
5744 /* Use the >= 2.2.0 function if available */
5745 if(pFT_Get_TrueType_Engine_Type)
5747 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5748 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5750 #ifdef FT_DRIVER_HAS_HINTER
5751 else
5753 FT_Module mod;
5755 /* otherwise if we've been compiled with < 2.2.0 headers
5756 use the internal macro */
5757 mod = pFT_Get_Module(library, "truetype");
5758 if(mod && FT_DRIVER_HAS_HINTER(mod))
5759 return TRUE;
5761 #endif
5763 return FALSE;
5766 /*************************************************************************
5767 * GetRasterizerCaps (GDI32.@)
5769 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5771 static int hinting = -1;
5773 if(hinting == -1)
5775 hinting = is_hinting_enabled();
5776 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5779 lprs->nSize = sizeof(RASTERIZER_STATUS);
5780 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5781 lprs->nLanguageID = 0;
5782 return TRUE;
5785 /*************************************************************
5786 * WineEngRealizationInfo
5788 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5790 FIXME("(%p, %p): stub!\n", font, info);
5792 info->flags = 1;
5793 if(FT_IS_SCALABLE(font->ft_face))
5794 info->flags |= 2;
5796 info->cache_num = font->cache_num;
5797 info->unknown2 = -1;
5798 return TRUE;
5801 /*************************************************************************
5802 * Kerning support for TrueType fonts
5804 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5806 struct TT_kern_table
5808 USHORT version;
5809 USHORT nTables;
5812 struct TT_kern_subtable
5814 USHORT version;
5815 USHORT length;
5816 union
5818 USHORT word;
5819 struct
5821 USHORT horizontal : 1;
5822 USHORT minimum : 1;
5823 USHORT cross_stream: 1;
5824 USHORT override : 1;
5825 USHORT reserved1 : 4;
5826 USHORT format : 8;
5827 } bits;
5828 } coverage;
5831 struct TT_format0_kern_subtable
5833 USHORT nPairs;
5834 USHORT searchRange;
5835 USHORT entrySelector;
5836 USHORT rangeShift;
5839 struct TT_kern_pair
5841 USHORT left;
5842 USHORT right;
5843 short value;
5846 static DWORD parse_format0_kern_subtable(GdiFont *font,
5847 const struct TT_format0_kern_subtable *tt_f0_ks,
5848 const USHORT *glyph_to_char,
5849 KERNINGPAIR *kern_pair, DWORD cPairs)
5851 USHORT i, nPairs;
5852 const struct TT_kern_pair *tt_kern_pair;
5854 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5856 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5858 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5859 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5860 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5862 if (!kern_pair || !cPairs)
5863 return nPairs;
5865 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5867 nPairs = min(nPairs, cPairs);
5869 for (i = 0; i < nPairs; i++)
5871 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5872 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5873 /* this algorithm appears to better match what Windows does */
5874 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5875 if (kern_pair->iKernAmount < 0)
5877 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5878 kern_pair->iKernAmount -= font->ppem;
5880 else if (kern_pair->iKernAmount > 0)
5882 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5883 kern_pair->iKernAmount += font->ppem;
5885 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5887 TRACE("left %u right %u value %d\n",
5888 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5890 kern_pair++;
5892 TRACE("copied %u entries\n", nPairs);
5893 return nPairs;
5896 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5898 DWORD length;
5899 void *buf;
5900 const struct TT_kern_table *tt_kern_table;
5901 const struct TT_kern_subtable *tt_kern_subtable;
5902 USHORT i, nTables;
5903 USHORT *glyph_to_char;
5905 EnterCriticalSection( &freetype_cs );
5906 if (font->total_kern_pairs != (DWORD)-1)
5908 if (cPairs && kern_pair)
5910 cPairs = min(cPairs, font->total_kern_pairs);
5911 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5912 LeaveCriticalSection( &freetype_cs );
5913 return cPairs;
5915 LeaveCriticalSection( &freetype_cs );
5916 return font->total_kern_pairs;
5919 font->total_kern_pairs = 0;
5921 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5923 if (length == GDI_ERROR)
5925 TRACE("no kerning data in the font\n");
5926 LeaveCriticalSection( &freetype_cs );
5927 return 0;
5930 buf = HeapAlloc(GetProcessHeap(), 0, length);
5931 if (!buf)
5933 WARN("Out of memory\n");
5934 LeaveCriticalSection( &freetype_cs );
5935 return 0;
5938 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5940 /* build a glyph index to char code map */
5941 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5942 if (!glyph_to_char)
5944 WARN("Out of memory allocating a glyph index to char code map\n");
5945 HeapFree(GetProcessHeap(), 0, buf);
5946 LeaveCriticalSection( &freetype_cs );
5947 return 0;
5950 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5952 FT_UInt glyph_code;
5953 FT_ULong char_code;
5955 glyph_code = 0;
5956 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5958 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5959 font->ft_face->num_glyphs, glyph_code, char_code);
5961 while (glyph_code)
5963 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5965 /* FIXME: This doesn't match what Windows does: it does some fancy
5966 * things with duplicate glyph index to char code mappings, while
5967 * we just avoid overriding existing entries.
5969 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5970 glyph_to_char[glyph_code] = (USHORT)char_code;
5972 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5975 else
5977 ULONG n;
5979 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5980 for (n = 0; n <= 65535; n++)
5981 glyph_to_char[n] = (USHORT)n;
5984 tt_kern_table = buf;
5985 nTables = GET_BE_WORD(tt_kern_table->nTables);
5986 TRACE("version %u, nTables %u\n",
5987 GET_BE_WORD(tt_kern_table->version), nTables);
5989 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5991 for (i = 0; i < nTables; i++)
5993 struct TT_kern_subtable tt_kern_subtable_copy;
5995 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5996 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5997 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5999 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6000 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6001 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6003 /* According to the TrueType specification this is the only format
6004 * that will be properly interpreted by Windows and OS/2
6006 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6008 DWORD new_chunk, old_total = font->total_kern_pairs;
6010 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6011 glyph_to_char, NULL, 0);
6012 font->total_kern_pairs += new_chunk;
6014 if (!font->kern_pairs)
6015 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6016 font->total_kern_pairs * sizeof(*font->kern_pairs));
6017 else
6018 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6019 font->total_kern_pairs * sizeof(*font->kern_pairs));
6021 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6022 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6024 else
6025 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6027 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6030 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6031 HeapFree(GetProcessHeap(), 0, buf);
6033 if (cPairs && kern_pair)
6035 cPairs = min(cPairs, font->total_kern_pairs);
6036 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6037 LeaveCriticalSection( &freetype_cs );
6038 return cPairs;
6040 LeaveCriticalSection( &freetype_cs );
6041 return font->total_kern_pairs;
6044 #else /* HAVE_FREETYPE */
6046 /*************************************************************************/
6048 BOOL WineEngInit(void)
6050 return FALSE;
6052 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6054 return NULL;
6056 BOOL WineEngDestroyFontInstance(HFONT hfont)
6058 return FALSE;
6061 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6063 return 1;
6066 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6067 LPWORD pgi, DWORD flags)
6069 return GDI_ERROR;
6072 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6073 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6074 const MAT2* lpmat)
6076 ERR("called but we don't have FreeType\n");
6077 return GDI_ERROR;
6080 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6082 ERR("called but we don't have FreeType\n");
6083 return FALSE;
6086 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6087 OUTLINETEXTMETRICW *potm)
6089 ERR("called but we don't have FreeType\n");
6090 return 0;
6093 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6094 LPINT buffer)
6096 ERR("called but we don't have FreeType\n");
6097 return FALSE;
6100 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6101 LPABC buffer)
6103 ERR("called but we don't have FreeType\n");
6104 return FALSE;
6107 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6108 LPABC buffer)
6110 ERR("called but we don't have FreeType\n");
6111 return FALSE;
6114 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6115 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6117 ERR("called but we don't have FreeType\n");
6118 return FALSE;
6121 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6122 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6124 ERR("called but we don't have FreeType\n");
6125 return FALSE;
6128 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6129 DWORD cbData)
6131 ERR("called but we don't have FreeType\n");
6132 return GDI_ERROR;
6135 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6137 ERR("called but we don't have FreeType\n");
6138 return 0;
6141 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6143 FIXME(":stub\n");
6144 return 1;
6147 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6149 FIXME(":stub\n");
6150 return TRUE;
6153 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6155 FIXME(":stub\n");
6156 return NULL;
6159 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6161 FIXME(":stub\n");
6162 return DEFAULT_CHARSET;
6165 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6167 return FALSE;
6170 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6172 FIXME("(%p, %p): stub\n", font, glyphset);
6173 return 0;
6176 BOOL WineEngFontIsLinked(GdiFont *font)
6178 return FALSE;
6181 /*************************************************************************
6182 * GetRasterizerCaps (GDI32.@)
6184 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6186 lprs->nSize = sizeof(RASTERIZER_STATUS);
6187 lprs->wFlags = 0;
6188 lprs->nLanguageID = 0;
6189 return TRUE;
6192 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6194 ERR("called but we don't have FreeType\n");
6195 return 0;
6198 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6200 ERR("called but we don't have FreeType\n");
6201 return FALSE;
6204 #endif /* HAVE_FREETYPE */