push 73336d9f381967eae40f391d78198b916ed9848d
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob64569d2b9647be1fc5f6ca0eb0a430be0fcd060a
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 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
200 #undef MAKE_FUNCPTR
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229 FT_Short height;
230 FT_Short width;
231 FT_Pos size;
232 FT_Pos x_ppem;
233 FT_Pos y_ppem;
234 FT_Short internal_leading;
235 } Bitmap_Size;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
240 typedef struct {
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
245 struct enum_data
247 ENUMLOGFONTEXW elf;
248 NEWTEXTMETRICEXW ntm;
249 DWORD type;
252 typedef struct tagFace {
253 struct list entry;
254 WCHAR *StyleName;
255 char *file;
256 void *font_data_ptr;
257 DWORD font_data_size;
258 FT_Long face_index;
259 BOOL Italic;
260 BOOL Bold;
261 FONTSIGNATURE fs;
262 FONTSIGNATURE fs_links;
263 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version;
265 BOOL scalable;
266 Bitmap_Size size; /* set if face is a bitmap */
267 BOOL external; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily *family;
269 /* Cached data for Enum */
270 struct enum_data *cached_enum_data;
271 } Face;
273 typedef struct tagFamily {
274 struct list entry;
275 const WCHAR *FamilyName;
276 struct list faces;
277 } Family;
279 typedef struct {
280 GLYPHMETRICS gm;
281 INT adv; /* These three hold to widths of the unrotated chars */
282 INT lsb;
283 INT bbx;
284 BOOL init;
285 } GM;
287 typedef struct {
288 FLOAT eM11, eM12;
289 FLOAT eM21, eM22;
290 } FMAT2;
292 typedef struct {
293 DWORD hash;
294 LOGFONTW lf;
295 FMAT2 matrix;
296 BOOL can_use_bitmap;
297 } FONT_DESC;
299 typedef struct tagHFONTLIST {
300 struct list entry;
301 HFONT hfont;
302 } HFONTLIST;
304 typedef struct {
305 struct list entry;
306 Face *face;
307 GdiFont *font;
308 } CHILD_FONT;
310 struct tagGdiFont {
311 struct list entry;
312 GM **gm;
313 DWORD gmsize;
314 struct list hfontlist;
315 OUTLINETEXTMETRICW *potm;
316 DWORD total_kern_pairs;
317 KERNINGPAIR *kern_pairs;
318 struct list child_fonts;
320 /* the following members can be accessed without locking, they are never modified after creation */
321 FT_Face ft_face;
322 struct font_mapping *mapping;
323 LPWSTR name;
324 int charset;
325 int codepage;
326 BOOL fake_italic;
327 BOOL fake_bold;
328 BYTE underline;
329 BYTE strikeout;
330 INT orientation;
331 FONT_DESC font_desc;
332 LONG aveWidth, ppem;
333 float scale_y;
334 SHORT yMax;
335 SHORT yMin;
336 DWORD ntmFlags;
337 FONTSIGNATURE fs;
338 GdiFont *base_font;
339 VOID *GSUB_Table;
342 typedef struct {
343 struct list entry;
344 const WCHAR *font_name;
345 struct list links;
346 } SYSTEM_LINKS;
348 #define GM_BLOCK_SIZE 128
349 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
351 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
352 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
353 #define UNUSED_CACHE_SIZE 10
354 static struct list child_font_list = LIST_INIT(child_font_list);
355 static struct list system_links = LIST_INIT(system_links);
357 static struct list font_subst_list = LIST_INIT(font_subst_list);
359 static struct list font_list = LIST_INIT(font_list);
361 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
362 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
363 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
365 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
367 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
368 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
369 'W','i','n','d','o','w','s','\\',
370 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
371 'F','o','n','t','s','\0'};
373 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
374 'W','i','n','d','o','w','s',' ','N','T','\\',
375 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
376 'F','o','n','t','s','\0'};
378 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
379 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
380 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
381 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
383 static const WCHAR * const SystemFontValues[4] = {
384 System_Value,
385 OEMFont_Value,
386 FixedSys_Value,
387 NULL
390 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
391 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
393 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
394 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
395 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
396 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
397 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
398 'E','u','r','o','p','e','a','n','\0'};
399 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
400 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
401 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
402 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
403 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
404 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
405 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
406 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
407 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
408 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
409 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
410 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
412 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
413 WesternW, /*00*/
414 Central_EuropeanW,
415 CyrillicW,
416 GreekW,
417 TurkishW,
418 HebrewW,
419 ArabicW,
420 BalticW,
421 VietnameseW, /*08*/
422 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
423 ThaiW,
424 JapaneseW,
425 CHINESE_GB2312W,
426 HangulW,
427 CHINESE_BIG5W,
428 Hangul_Johab_W,
429 NULL, NULL, /*23*/
430 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
431 SymbolW /*31*/
434 typedef struct {
435 WCHAR *name;
436 INT charset;
437 } NameCs;
439 typedef struct tagFontSubst {
440 struct list entry;
441 NameCs from;
442 NameCs to;
443 } FontSubst;
445 struct font_mapping
447 struct list entry;
448 int refcount;
449 dev_t dev;
450 ino_t ino;
451 void *data;
452 size_t size;
455 static struct list mappings_list = LIST_INIT( mappings_list );
457 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
459 static CRITICAL_SECTION freetype_cs;
460 static CRITICAL_SECTION_DEBUG critsect_debug =
462 0, 0, &freetype_cs,
463 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
464 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
466 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
468 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
470 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
471 static BOOL use_default_fallback = FALSE;
473 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
475 /****************************************
476 * Notes on .fon files
478 * The fonts System, FixedSys and Terminal are special. There are typically multiple
479 * versions installed for different resolutions and codepages. Windows stores which one to use
480 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
481 * Key Meaning
482 * FIXEDFON.FON FixedSys
483 * FONTS.FON System
484 * OEMFONT.FON Terminal
485 * LogPixels Current dpi set by the display control panel applet
486 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
487 * also has a LogPixels value that appears to mirror this)
489 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
490 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
491 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
492 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
493 * so that makes sense.
495 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
496 * to be mapped into the registry on Windows 2000 at least).
497 * I have
498 * woafont=app850.fon
499 * ega80woa.fon=ega80850.fon
500 * ega40woa.fon=ega40850.fon
501 * cga80woa.fon=cga80850.fon
502 * cga40woa.fon=cga40850.fon
505 /* These are all structures needed for the GSUB table */
507 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
508 #define TATEGAKI_LOWER_BOUND 0x02F1
510 typedef struct {
511 DWORD version;
512 WORD ScriptList;
513 WORD FeatureList;
514 WORD LookupList;
515 } GSUB_Header;
517 typedef struct {
518 CHAR ScriptTag[4];
519 WORD Script;
520 } GSUB_ScriptRecord;
522 typedef struct {
523 WORD ScriptCount;
524 GSUB_ScriptRecord ScriptRecord[1];
525 } GSUB_ScriptList;
527 typedef struct {
528 CHAR LangSysTag[4];
529 WORD LangSys;
530 } GSUB_LangSysRecord;
532 typedef struct {
533 WORD DefaultLangSys;
534 WORD LangSysCount;
535 GSUB_LangSysRecord LangSysRecord[1];
536 } GSUB_Script;
538 typedef struct {
539 WORD LookupOrder; /* Reserved */
540 WORD ReqFeatureIndex;
541 WORD FeatureCount;
542 WORD FeatureIndex[1];
543 } GSUB_LangSys;
545 typedef struct {
546 CHAR FeatureTag[4];
547 WORD Feature;
548 } GSUB_FeatureRecord;
550 typedef struct {
551 WORD FeatureCount;
552 GSUB_FeatureRecord FeatureRecord[1];
553 } GSUB_FeatureList;
555 typedef struct {
556 WORD FeatureParams; /* Reserved */
557 WORD LookupCount;
558 WORD LookupListIndex[1];
559 } GSUB_Feature;
561 typedef struct {
562 WORD LookupCount;
563 WORD Lookup[1];
564 } GSUB_LookupList;
566 typedef struct {
567 WORD LookupType;
568 WORD LookupFlag;
569 WORD SubTableCount;
570 WORD SubTable[1];
571 } GSUB_LookupTable;
573 typedef struct {
574 WORD CoverageFormat;
575 WORD GlyphCount;
576 WORD GlyphArray[1];
577 } GSUB_CoverageFormat1;
579 typedef struct {
580 WORD Start;
581 WORD End;
582 WORD StartCoverageIndex;
583 } GSUB_RangeRecord;
585 typedef struct {
586 WORD CoverageFormat;
587 WORD RangeCount;
588 GSUB_RangeRecord RangeRecord[1];
589 } GSUB_CoverageFormat2;
591 typedef struct {
592 WORD SubstFormat; /* = 1 */
593 WORD Coverage;
594 WORD DeltaGlyphID;
595 } GSUB_SingleSubstFormat1;
597 typedef struct {
598 WORD SubstFormat; /* = 2 */
599 WORD Coverage;
600 WORD GlyphCount;
601 WORD Substitute[1];
602 }GSUB_SingleSubstFormat2;
604 #ifdef HAVE_CARBON_CARBON_H
605 static char *find_cache_dir(void)
607 FSRef ref;
608 OSErr err;
609 static char cached_path[MAX_PATH];
610 static const char *wine = "/Wine", *fonts = "/Fonts";
612 if(*cached_path) return cached_path;
614 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
615 if(err != noErr)
617 WARN("can't create cached data folder\n");
618 return NULL;
620 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
621 if(err != noErr)
623 WARN("can't create cached data path\n");
624 *cached_path = '\0';
625 return NULL;
627 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
629 ERR("Could not create full path\n");
630 *cached_path = '\0';
631 return NULL;
633 strcat(cached_path, wine);
635 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
637 WARN("Couldn't mkdir %s\n", cached_path);
638 *cached_path = '\0';
639 return NULL;
641 strcat(cached_path, fonts);
642 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
644 WARN("Couldn't mkdir %s\n", cached_path);
645 *cached_path = '\0';
646 return NULL;
648 return cached_path;
651 /******************************************************************
652 * expand_mac_font
654 * Extracts individual TrueType font files from a Mac suitcase font
655 * and saves them into the user's caches directory (see
656 * find_cache_dir()).
657 * Returns a NULL terminated array of filenames.
659 * We do this because they are apps that try to read ttf files
660 * themselves and they don't like Mac suitcase files.
662 static char **expand_mac_font(const char *path)
664 FSRef ref;
665 SInt16 res_ref;
666 OSStatus s;
667 unsigned int idx;
668 const char *out_dir;
669 const char *filename;
670 int output_len;
671 struct {
672 char **array;
673 unsigned int size, max_size;
674 } ret;
676 TRACE("path %s\n", path);
678 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
679 if(s != noErr)
681 WARN("failed to get ref\n");
682 return NULL;
685 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
686 if(s != noErr)
688 TRACE("no data fork, so trying resource fork\n");
689 res_ref = FSOpenResFile(&ref, fsRdPerm);
690 if(res_ref == -1)
692 TRACE("unable to open resource fork\n");
693 return NULL;
697 ret.size = 0;
698 ret.max_size = 10;
699 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
700 if(!ret.array)
702 CloseResFile(res_ref);
703 return NULL;
706 out_dir = find_cache_dir();
708 filename = strrchr(path, '/');
709 if(!filename) filename = path;
710 else filename++;
712 /* output filename has the form out_dir/filename_%04x.ttf */
713 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
715 UseResFile(res_ref);
716 idx = 1;
717 while(1)
719 FamRec *fam_rec;
720 unsigned short *num_faces_ptr, num_faces, face;
721 AsscEntry *assoc;
722 Handle fond;
723 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
725 fond = Get1IndResource(fond_res, idx);
726 if(!fond) break;
727 TRACE("got fond resource %d\n", idx);
728 HLock(fond);
730 fam_rec = *(FamRec**)fond;
731 num_faces_ptr = (unsigned short *)(fam_rec + 1);
732 num_faces = GET_BE_WORD(*num_faces_ptr);
733 num_faces++;
734 assoc = (AsscEntry*)(num_faces_ptr + 1);
735 TRACE("num faces %04x\n", num_faces);
736 for(face = 0; face < num_faces; face++, assoc++)
738 Handle sfnt;
739 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
740 unsigned short size, font_id;
741 char *output;
743 size = GET_BE_WORD(assoc->fontSize);
744 font_id = GET_BE_WORD(assoc->fontID);
745 if(size != 0)
747 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
748 continue;
751 TRACE("trying to load sfnt id %04x\n", font_id);
752 sfnt = GetResource(sfnt_res, font_id);
753 if(!sfnt)
755 TRACE("can't get sfnt resource %04x\n", font_id);
756 continue;
759 output = HeapAlloc(GetProcessHeap(), 0, output_len);
760 if(output)
762 int fd;
764 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
766 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
767 if(fd != -1 || errno == EEXIST)
769 if(fd != -1)
771 unsigned char *sfnt_data;
773 HLock(sfnt);
774 sfnt_data = *(unsigned char**)sfnt;
775 write(fd, sfnt_data, GetHandleSize(sfnt));
776 HUnlock(sfnt);
777 close(fd);
779 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
781 ret.max_size *= 2;
782 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
784 ret.array[ret.size++] = output;
786 else
788 WARN("unable to create %s\n", output);
789 HeapFree(GetProcessHeap(), 0, output);
792 ReleaseResource(sfnt);
794 HUnlock(fond);
795 ReleaseResource(fond);
796 idx++;
798 CloseResFile(res_ref);
800 return ret.array;
803 #endif /* HAVE_CARBON_CARBON_H */
805 static inline BOOL is_win9x(void)
807 return GetVersion() & 0x80000000;
810 This function builds an FT_Fixed from a float. It puts the integer part
811 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
812 It fails if the integer part of the float number is greater than SHORT_MAX.
814 static inline FT_Fixed FT_FixedFromFloat(float f)
816 short value = f;
817 unsigned short fract = (f - value) * 0xFFFF;
818 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
822 This function builds an FT_Fixed from a FIXED. It simply put f.value
823 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
825 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
827 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
831 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
833 Family *family;
834 Face *face;
835 const char *file;
836 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
837 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
839 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
840 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
842 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
844 if(face_name && strcmpiW(face_name, family->FamilyName))
845 continue;
846 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
848 if (!face->file)
849 continue;
850 file = strrchr(face->file, '/');
851 if(!file)
852 file = face->file;
853 else
854 file++;
855 if(!strcasecmp(file, file_nameA))
857 HeapFree(GetProcessHeap(), 0, file_nameA);
858 return face;
862 HeapFree(GetProcessHeap(), 0, file_nameA);
863 return NULL;
866 static Family *find_family_from_name(const WCHAR *name)
868 Family *family;
870 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
872 if(!strcmpiW(family->FamilyName, name))
873 return family;
876 return NULL;
879 static void DumpSubstList(void)
881 FontSubst *psub;
883 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
885 if(psub->from.charset != -1 || psub->to.charset != -1)
886 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
887 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
888 else
889 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
890 debugstr_w(psub->to.name));
892 return;
895 static LPWSTR strdupW(LPCWSTR p)
897 LPWSTR ret;
898 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
899 ret = HeapAlloc(GetProcessHeap(), 0, len);
900 memcpy(ret, p, len);
901 return ret;
904 static LPSTR strdupA(LPCSTR p)
906 LPSTR ret;
907 DWORD len = (strlen(p) + 1);
908 ret = HeapAlloc(GetProcessHeap(), 0, len);
909 memcpy(ret, p, len);
910 return ret;
913 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
914 INT from_charset)
916 FontSubst *element;
918 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
920 if(!strcmpiW(element->from.name, from_name) &&
921 (element->from.charset == from_charset ||
922 element->from.charset == -1))
923 return element;
926 return NULL;
929 #define ADD_FONT_SUBST_FORCE 1
931 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
933 FontSubst *from_exist, *to_exist;
935 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
937 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
939 list_remove(&from_exist->entry);
940 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
941 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
942 HeapFree(GetProcessHeap(), 0, from_exist);
943 from_exist = NULL;
946 if(!from_exist)
948 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
950 if(to_exist)
952 HeapFree(GetProcessHeap(), 0, subst->to.name);
953 subst->to.name = strdupW(to_exist->to.name);
956 list_add_tail(subst_list, &subst->entry);
958 return TRUE;
961 HeapFree(GetProcessHeap(), 0, subst->from.name);
962 HeapFree(GetProcessHeap(), 0, subst->to.name);
963 HeapFree(GetProcessHeap(), 0, subst);
964 return FALSE;
967 static void split_subst_info(NameCs *nc, LPSTR str)
969 CHAR *p = strrchr(str, ',');
970 DWORD len;
972 nc->charset = -1;
973 if(p && *(p+1)) {
974 nc->charset = strtol(p+1, NULL, 10);
975 *p = '\0';
977 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
978 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
979 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
982 static void LoadSubstList(void)
984 FontSubst *psub;
985 HKEY hkey;
986 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
987 LPSTR value;
988 LPVOID data;
990 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
991 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
992 &hkey) == ERROR_SUCCESS) {
994 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
995 &valuelen, &datalen, NULL, NULL);
997 valuelen++; /* returned value doesn't include room for '\0' */
998 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
999 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1001 dlen = datalen;
1002 vlen = valuelen;
1003 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1004 &dlen) == ERROR_SUCCESS) {
1005 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1007 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1008 split_subst_info(&psub->from, value);
1009 split_subst_info(&psub->to, data);
1011 /* Win 2000 doesn't allow mapping between different charsets
1012 or mapping of DEFAULT_CHARSET */
1013 if((psub->to.charset != psub->from.charset) ||
1014 psub->to.charset == DEFAULT_CHARSET) {
1015 HeapFree(GetProcessHeap(), 0, psub->to.name);
1016 HeapFree(GetProcessHeap(), 0, psub->from.name);
1017 HeapFree(GetProcessHeap(), 0, psub);
1018 } else {
1019 add_font_subst(&font_subst_list, psub, 0);
1021 /* reset dlen and vlen */
1022 dlen = datalen;
1023 vlen = valuelen;
1025 HeapFree(GetProcessHeap(), 0, data);
1026 HeapFree(GetProcessHeap(), 0, value);
1027 RegCloseKey(hkey);
1031 static WCHAR *get_familyname(FT_Face ft_face)
1033 WCHAR *family = NULL;
1034 FT_SfntName name;
1035 FT_UInt num_names, name_index, i;
1037 if(FT_IS_SFNT(ft_face))
1039 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1041 for(name_index = 0; name_index < num_names; name_index++)
1043 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1045 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1046 (name.language_id == GetUserDefaultLCID()) &&
1047 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1048 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1050 /* String is not nul terminated and string_len is a byte length. */
1051 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1052 for(i = 0; i < name.string_len / 2; i++)
1054 WORD *tmp = (WORD *)&name.string[i * 2];
1055 family[i] = GET_BE_WORD(*tmp);
1057 family[i] = 0;
1059 TRACE("Got localised name %s\n", debugstr_w(family));
1060 return family;
1066 return NULL;
1070 /*****************************************************************
1071 * load_sfnt_table
1073 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1074 * of FreeType that don't export this function.
1077 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1080 FT_Error err;
1082 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1083 if(pFT_Load_Sfnt_Table)
1085 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1087 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1088 else /* Do it the hard way */
1090 TT_Face tt_face = (TT_Face) ft_face;
1091 SFNT_Interface *sfnt;
1092 if (FT_Version.major==2 && FT_Version.minor==0)
1094 /* 2.0.x */
1095 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1097 else
1099 /* A field was added in the middle of the structure in 2.1.x */
1100 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1102 err = sfnt->load_any(tt_face, table, offset, buf, len);
1104 #else
1105 else
1107 static int msg;
1108 if(!msg)
1110 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1111 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1112 "Please upgrade your freetype library.\n");
1113 msg++;
1115 err = FT_Err_Unimplemented_Feature;
1117 #endif
1118 return err;
1122 #define ADDFONT_EXTERNAL_FONT 0x01
1123 #define ADDFONT_FORCE_BITMAP 0x02
1124 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1126 FT_Face ft_face;
1127 TT_OS2 *pOS2;
1128 TT_Header *pHeader = NULL;
1129 WCHAR *english_family, *localised_family, *StyleW;
1130 DWORD len;
1131 Family *family;
1132 Face *face;
1133 struct list *family_elem_ptr, *face_elem_ptr;
1134 FT_Error err;
1135 FT_Long face_index = 0, num_faces;
1136 #ifdef HAVE_FREETYPE_FTWINFNT_H
1137 FT_WinFNT_HeaderRec winfnt_header;
1138 #endif
1139 int i, bitmap_num, internal_leading;
1140 FONTSIGNATURE fs;
1142 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1143 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1145 #ifdef HAVE_CARBON_CARBON_H
1146 if(file && !fake_family)
1148 char **mac_list = expand_mac_font(file);
1149 if(mac_list)
1151 BOOL had_one = FALSE;
1152 char **cursor;
1153 for(cursor = mac_list; *cursor; cursor++)
1155 had_one = TRUE;
1156 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1157 HeapFree(GetProcessHeap(), 0, *cursor);
1159 HeapFree(GetProcessHeap(), 0, mac_list);
1160 if(had_one)
1161 return 1;
1164 #endif /* HAVE_CARBON_CARBON_H */
1166 do {
1167 char *family_name = fake_family;
1169 if (file)
1171 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1172 err = pFT_New_Face(library, file, face_index, &ft_face);
1173 } else
1175 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1176 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1179 if(err != 0) {
1180 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1181 return 0;
1184 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*/
1185 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1186 pFT_Done_Face(ft_face);
1187 return 0;
1190 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1191 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1192 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1193 pFT_Done_Face(ft_face);
1194 return 0;
1197 if(FT_IS_SFNT(ft_face))
1199 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1200 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1201 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1203 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1204 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1205 pFT_Done_Face(ft_face);
1206 return 0;
1209 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1210 we don't want to load these. */
1211 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1213 FT_ULong len = 0;
1215 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1217 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1218 pFT_Done_Face(ft_face);
1219 return 0;
1224 if(!ft_face->family_name || !ft_face->style_name) {
1225 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1226 pFT_Done_Face(ft_face);
1227 return 0;
1230 if (target_family)
1232 localised_family = get_familyname(ft_face);
1233 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1235 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1236 HeapFree(GetProcessHeap(), 0, localised_family);
1237 num_faces = ft_face->num_faces;
1238 pFT_Done_Face(ft_face);
1239 continue;
1241 HeapFree(GetProcessHeap(), 0, localised_family);
1244 if(!family_name)
1245 family_name = ft_face->family_name;
1247 bitmap_num = 0;
1248 do {
1249 My_FT_Bitmap_Size *size = NULL;
1250 FT_ULong tmp_size;
1252 if(!FT_IS_SCALABLE(ft_face))
1253 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1255 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1256 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1257 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1259 localised_family = NULL;
1260 if(!fake_family) {
1261 localised_family = get_familyname(ft_face);
1262 if(localised_family && !strcmpW(localised_family, english_family)) {
1263 HeapFree(GetProcessHeap(), 0, localised_family);
1264 localised_family = NULL;
1268 family = NULL;
1269 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1270 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1271 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1272 break;
1273 family = NULL;
1275 if(!family) {
1276 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1277 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1278 list_init(&family->faces);
1279 list_add_tail(&font_list, &family->entry);
1281 if(localised_family) {
1282 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1283 subst->from.name = strdupW(english_family);
1284 subst->from.charset = -1;
1285 subst->to.name = strdupW(localised_family);
1286 subst->to.charset = -1;
1287 add_font_subst(&font_subst_list, subst, 0);
1290 HeapFree(GetProcessHeap(), 0, localised_family);
1291 HeapFree(GetProcessHeap(), 0, english_family);
1293 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1294 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1295 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1297 internal_leading = 0;
1298 memset(&fs, 0, sizeof(fs));
1300 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1301 if(pOS2) {
1302 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1303 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1304 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1305 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1306 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1307 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1308 if(pOS2->version == 0) {
1309 FT_UInt dummy;
1311 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1312 fs.fsCsb[0] |= FS_LATIN1;
1313 else
1314 fs.fsCsb[0] |= FS_SYMBOL;
1317 #ifdef HAVE_FREETYPE_FTWINFNT_H
1318 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1319 CHARSETINFO csi;
1320 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1321 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1322 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1323 fs = csi.fs;
1324 internal_leading = winfnt_header.internal_leading;
1326 #endif
1328 face_elem_ptr = list_head(&family->faces);
1329 while(face_elem_ptr) {
1330 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1331 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1332 if(!strcmpW(face->StyleName, StyleW) &&
1333 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1334 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1335 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1336 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1338 if(fake_family) {
1339 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1340 HeapFree(GetProcessHeap(), 0, StyleW);
1341 pFT_Done_Face(ft_face);
1342 return 1;
1344 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1345 TRACE("Original font is newer so skipping this one\n");
1346 HeapFree(GetProcessHeap(), 0, StyleW);
1347 pFT_Done_Face(ft_face);
1348 return 1;
1349 } else {
1350 TRACE("Replacing original with this one\n");
1351 list_remove(&face->entry);
1352 HeapFree(GetProcessHeap(), 0, face->file);
1353 HeapFree(GetProcessHeap(), 0, face->StyleName);
1354 HeapFree(GetProcessHeap(), 0, face);
1355 break;
1359 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1360 face->cached_enum_data = NULL;
1361 list_add_tail(&family->faces, &face->entry);
1362 face->StyleName = StyleW;
1363 if (file)
1365 face->file = strdupA(file);
1366 face->font_data_ptr = NULL;
1367 face->font_data_size = 0;
1369 else
1371 face->file = NULL;
1372 face->font_data_ptr = font_data_ptr;
1373 face->font_data_size = font_data_size;
1375 face->face_index = face_index;
1376 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1377 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1378 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1379 face->family = family;
1380 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1381 face->fs = fs;
1382 memset(&face->fs_links, 0, sizeof(face->fs_links));
1384 if(FT_IS_SCALABLE(ft_face)) {
1385 memset(&face->size, 0, sizeof(face->size));
1386 face->scalable = TRUE;
1387 } else {
1388 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1389 size->height, size->width, size->size >> 6,
1390 size->x_ppem >> 6, size->y_ppem >> 6);
1391 face->size.height = size->height;
1392 face->size.width = size->width;
1393 face->size.size = size->size;
1394 face->size.x_ppem = size->x_ppem;
1395 face->size.y_ppem = size->y_ppem;
1396 face->size.internal_leading = internal_leading;
1397 face->scalable = FALSE;
1400 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1401 tmp_size = 0;
1402 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1404 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1405 face->ntmFlags = NTM_PS_OPENTYPE;
1407 else
1408 face->ntmFlags = 0;
1410 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1411 face->fs.fsCsb[0], face->fs.fsCsb[1],
1412 face->fs.fsUsb[0], face->fs.fsUsb[1],
1413 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1416 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1417 for(i = 0; i < ft_face->num_charmaps; i++) {
1418 switch(ft_face->charmaps[i]->encoding) {
1419 case FT_ENCODING_UNICODE:
1420 case FT_ENCODING_APPLE_ROMAN:
1421 face->fs.fsCsb[0] |= FS_LATIN1;
1422 break;
1423 case FT_ENCODING_MS_SYMBOL:
1424 face->fs.fsCsb[0] |= FS_SYMBOL;
1425 break;
1426 default:
1427 break;
1432 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1433 have_installed_roman_font = TRUE;
1434 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1436 num_faces = ft_face->num_faces;
1437 pFT_Done_Face(ft_face);
1438 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1439 debugstr_w(StyleW));
1440 } while(num_faces > ++face_index);
1441 return num_faces;
1444 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1446 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1449 static void DumpFontList(void)
1451 Family *family;
1452 Face *face;
1453 struct list *family_elem_ptr, *face_elem_ptr;
1455 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1456 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1457 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1458 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1459 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1460 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1461 if(!face->scalable)
1462 TRACE(" %d", face->size.height);
1463 TRACE("\n");
1466 return;
1469 /***********************************************************
1470 * The replacement list is a way to map an entire font
1471 * family onto another family. For example adding
1473 * [HKCU\Software\Wine\Fonts\Replacements]
1474 * "Wingdings"="Winedings"
1476 * would enumerate the Winedings font both as Winedings and
1477 * Wingdings. However if a real Wingdings font is present the
1478 * replacement does not take place.
1481 static void LoadReplaceList(void)
1483 HKEY hkey;
1484 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1485 LPWSTR value;
1486 LPVOID data;
1487 Family *family;
1488 Face *face;
1489 struct list *family_elem_ptr, *face_elem_ptr;
1490 CHAR familyA[400];
1492 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1493 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1495 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1496 &valuelen, &datalen, NULL, NULL);
1498 valuelen++; /* returned value doesn't include room for '\0' */
1499 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1500 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1502 dlen = datalen;
1503 vlen = valuelen;
1504 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1505 &dlen) == ERROR_SUCCESS) {
1506 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1507 /* "NewName"="Oldname" */
1508 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1510 /* Find the old family and hence all of the font files
1511 in that family */
1512 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1513 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1514 if(!strcmpiW(family->FamilyName, data)) {
1515 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1516 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1517 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1518 debugstr_w(face->StyleName), familyA);
1519 /* Now add a new entry with the new family name */
1520 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1522 break;
1525 /* reset dlen and vlen */
1526 dlen = datalen;
1527 vlen = valuelen;
1529 HeapFree(GetProcessHeap(), 0, data);
1530 HeapFree(GetProcessHeap(), 0, value);
1531 RegCloseKey(hkey);
1535 /*************************************************************
1536 * init_system_links
1538 static BOOL init_system_links(void)
1540 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1541 'W','i','n','d','o','w','s',' ','N','T','\\',
1542 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1543 'S','y','s','t','e','m','L','i','n','k',0};
1544 HKEY hkey;
1545 BOOL ret = FALSE;
1546 DWORD type, max_val, max_data, val_len, data_len, index;
1547 WCHAR *value, *data;
1548 WCHAR *entry, *next;
1549 SYSTEM_LINKS *font_link, *system_font_link;
1550 CHILD_FONT *child_font;
1551 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1552 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1553 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1554 FONTSIGNATURE fs;
1555 Family *family;
1556 Face *face;
1557 FontSubst *psub;
1559 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1561 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1562 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1563 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1564 val_len = max_val + 1;
1565 data_len = max_data;
1566 index = 0;
1567 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1569 TRACE("%s:\n", debugstr_w(value));
1571 memset(&fs, 0, sizeof(fs));
1572 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1573 psub = get_font_subst(&font_subst_list, value, -1);
1574 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1575 list_init(&font_link->links);
1576 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1578 WCHAR *face_name;
1579 CHILD_FONT *child_font;
1581 TRACE("\t%s\n", debugstr_w(entry));
1583 next = entry + strlenW(entry) + 1;
1585 face_name = strchrW(entry, ',');
1586 if(face_name)
1588 *face_name++ = 0;
1589 while(isspaceW(*face_name))
1590 face_name++;
1592 psub = get_font_subst(&font_subst_list, face_name, -1);
1593 if(psub)
1594 face_name = psub->to.name;
1596 face = find_face_from_filename(entry, face_name);
1597 if(!face)
1599 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1600 continue;
1603 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1604 child_font->face = face;
1605 child_font->font = NULL;
1606 fs.fsCsb[0] |= face->fs.fsCsb[0];
1607 fs.fsCsb[1] |= face->fs.fsCsb[1];
1608 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1609 list_add_tail(&font_link->links, &child_font->entry);
1611 family = find_family_from_name(font_link->font_name);
1612 if(family)
1614 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1616 face->fs_links = fs;
1619 list_add_tail(&system_links, &font_link->entry);
1620 val_len = max_val + 1;
1621 data_len = max_data;
1624 HeapFree(GetProcessHeap(), 0, value);
1625 HeapFree(GetProcessHeap(), 0, data);
1626 RegCloseKey(hkey);
1629 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1630 that Tahoma has */
1632 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1633 system_font_link->font_name = strdupW(System);
1634 list_init(&system_font_link->links);
1636 face = find_face_from_filename(tahoma_ttf, Tahoma);
1637 if(face)
1639 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1640 child_font->face = face;
1641 child_font->font = NULL;
1642 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1643 list_add_tail(&system_font_link->links, &child_font->entry);
1645 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1647 if(!strcmpiW(font_link->font_name, Tahoma))
1649 CHILD_FONT *font_link_entry;
1650 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1652 CHILD_FONT *new_child;
1653 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1654 new_child->face = font_link_entry->face;
1655 new_child->font = NULL;
1656 list_add_tail(&system_font_link->links, &new_child->entry);
1658 break;
1661 list_add_tail(&system_links, &system_font_link->entry);
1662 return ret;
1665 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1667 DIR *dir;
1668 struct dirent *dent;
1669 char path[MAX_PATH];
1671 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1673 dir = opendir(dirname);
1674 if(!dir) {
1675 WARN("Can't open directory %s\n", debugstr_a(dirname));
1676 return FALSE;
1678 while((dent = readdir(dir)) != NULL) {
1679 struct stat statbuf;
1681 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1682 continue;
1684 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1686 sprintf(path, "%s/%s", dirname, dent->d_name);
1688 if(stat(path, &statbuf) == -1)
1690 WARN("Can't stat %s\n", debugstr_a(path));
1691 continue;
1693 if(S_ISDIR(statbuf.st_mode))
1694 ReadFontDir(path, external_fonts);
1695 else
1696 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1698 closedir(dir);
1699 return TRUE;
1702 static void load_fontconfig_fonts(void)
1704 #ifdef SONAME_LIBFONTCONFIG
1705 void *fc_handle = NULL;
1706 FcConfig *config;
1707 FcPattern *pat;
1708 FcObjectSet *os;
1709 FcFontSet *fontset;
1710 int i, len;
1711 char *file;
1712 const char *ext;
1714 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1715 if(!fc_handle) {
1716 TRACE("Wine cannot find the fontconfig library (%s).\n",
1717 SONAME_LIBFONTCONFIG);
1718 return;
1720 #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;}
1721 LOAD_FUNCPTR(FcConfigGetCurrent);
1722 LOAD_FUNCPTR(FcFontList);
1723 LOAD_FUNCPTR(FcFontSetDestroy);
1724 LOAD_FUNCPTR(FcInit);
1725 LOAD_FUNCPTR(FcObjectSetAdd);
1726 LOAD_FUNCPTR(FcObjectSetCreate);
1727 LOAD_FUNCPTR(FcObjectSetDestroy);
1728 LOAD_FUNCPTR(FcPatternCreate);
1729 LOAD_FUNCPTR(FcPatternDestroy);
1730 LOAD_FUNCPTR(FcPatternGetBool);
1731 LOAD_FUNCPTR(FcPatternGetString);
1732 #undef LOAD_FUNCPTR
1734 if(!pFcInit()) return;
1736 config = pFcConfigGetCurrent();
1737 pat = pFcPatternCreate();
1738 os = pFcObjectSetCreate();
1739 pFcObjectSetAdd(os, FC_FILE);
1740 pFcObjectSetAdd(os, FC_SCALABLE);
1741 fontset = pFcFontList(config, pat, os);
1742 if(!fontset) return;
1743 for(i = 0; i < fontset->nfont; i++) {
1744 FcBool scalable;
1746 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1747 continue;
1748 TRACE("fontconfig: %s\n", file);
1750 /* We're just interested in OT/TT fonts for now, so this hack just
1751 picks up the scalable fonts without extensions .pf[ab] to save time
1752 loading every other font */
1754 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1756 TRACE("not scalable\n");
1757 continue;
1760 len = strlen( file );
1761 if(len < 4) continue;
1762 ext = &file[ len - 3 ];
1763 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1764 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1766 pFcFontSetDestroy(fontset);
1767 pFcObjectSetDestroy(os);
1768 pFcPatternDestroy(pat);
1769 sym_not_found:
1770 #endif
1771 return;
1774 static BOOL load_font_from_data_dir(LPCWSTR file)
1776 BOOL ret = FALSE;
1777 const char *data_dir = wine_get_data_dir();
1779 if (!data_dir) data_dir = wine_get_build_dir();
1781 if (data_dir)
1783 INT len;
1784 char *unix_name;
1786 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1788 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1790 strcpy(unix_name, data_dir);
1791 strcat(unix_name, "/fonts/");
1793 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1795 EnterCriticalSection( &freetype_cs );
1796 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1797 LeaveCriticalSection( &freetype_cs );
1798 HeapFree(GetProcessHeap(), 0, unix_name);
1800 return ret;
1803 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1805 static const WCHAR slashW[] = {'\\','\0'};
1806 BOOL ret = FALSE;
1807 WCHAR windowsdir[MAX_PATH];
1808 char *unixname;
1810 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1811 strcatW(windowsdir, fontsW);
1812 strcatW(windowsdir, slashW);
1813 strcatW(windowsdir, file);
1814 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1815 EnterCriticalSection( &freetype_cs );
1816 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1817 LeaveCriticalSection( &freetype_cs );
1818 HeapFree(GetProcessHeap(), 0, unixname);
1820 return ret;
1823 static void load_system_fonts(void)
1825 HKEY hkey;
1826 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1827 const WCHAR * const *value;
1828 DWORD dlen, type;
1829 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1830 char *unixname;
1832 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1833 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1834 strcatW(windowsdir, fontsW);
1835 for(value = SystemFontValues; *value; value++) {
1836 dlen = sizeof(data);
1837 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1838 type == REG_SZ) {
1839 BOOL added = FALSE;
1841 sprintfW(pathW, fmtW, windowsdir, data);
1842 if((unixname = wine_get_unix_file_name(pathW))) {
1843 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1844 HeapFree(GetProcessHeap(), 0, unixname);
1846 if (!added)
1847 load_font_from_data_dir(data);
1850 RegCloseKey(hkey);
1854 /*************************************************************
1856 * This adds registry entries for any externally loaded fonts
1857 * (fonts from fontconfig or FontDirs). It also deletes entries
1858 * of no longer existing fonts.
1861 static void update_reg_entries(void)
1863 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1864 LPWSTR valueW;
1865 DWORD len, len_fam;
1866 Family *family;
1867 Face *face;
1868 struct list *family_elem_ptr, *face_elem_ptr;
1869 WCHAR *file;
1870 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1871 static const WCHAR spaceW[] = {' ', '\0'};
1872 char *path;
1874 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1875 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1876 ERR("Can't create Windows font reg key\n");
1877 goto end;
1880 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1881 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1882 ERR("Can't create Windows font reg key\n");
1883 goto end;
1886 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1887 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1888 ERR("Can't create external font reg key\n");
1889 goto end;
1892 /* enumerate the fonts and add external ones to the two keys */
1894 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1895 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1896 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1897 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1898 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1899 if(!face->external) continue;
1900 len = len_fam;
1901 if(strcmpiW(face->StyleName, RegularW))
1902 len = len_fam + strlenW(face->StyleName) + 1;
1903 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1904 strcpyW(valueW, family->FamilyName);
1905 if(len != len_fam) {
1906 strcatW(valueW, spaceW);
1907 strcatW(valueW, face->StyleName);
1909 strcatW(valueW, TrueType);
1911 file = wine_get_dos_file_name(face->file);
1912 if(file)
1913 len = strlenW(file) + 1;
1914 else
1916 if((path = strrchr(face->file, '/')) == NULL)
1917 path = face->file;
1918 else
1919 path++;
1920 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1922 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1923 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1925 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1926 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1927 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1929 HeapFree(GetProcessHeap(), 0, file);
1930 HeapFree(GetProcessHeap(), 0, valueW);
1933 end:
1934 if(external_key) RegCloseKey(external_key);
1935 if(win9x_key) RegCloseKey(win9x_key);
1936 if(winnt_key) RegCloseKey(winnt_key);
1937 return;
1940 static void delete_external_font_keys(void)
1942 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1943 DWORD dlen, vlen, datalen, valuelen, i, type;
1944 LPWSTR valueW;
1945 LPVOID data;
1947 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1948 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1949 ERR("Can't create Windows font reg key\n");
1950 goto end;
1953 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1954 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1955 ERR("Can't create Windows font reg key\n");
1956 goto end;
1959 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
1960 ERR("Can't create external font reg key\n");
1961 goto end;
1964 /* Delete all external fonts added last time */
1966 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1967 &valuelen, &datalen, NULL, NULL);
1968 valuelen++; /* returned value doesn't include room for '\0' */
1969 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1970 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1972 dlen = datalen * sizeof(WCHAR);
1973 vlen = valuelen;
1974 i = 0;
1975 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
1976 &dlen) == ERROR_SUCCESS) {
1978 RegDeleteValueW(winnt_key, valueW);
1979 RegDeleteValueW(win9x_key, valueW);
1980 /* reset dlen and vlen */
1981 dlen = datalen;
1982 vlen = valuelen;
1984 HeapFree(GetProcessHeap(), 0, data);
1985 HeapFree(GetProcessHeap(), 0, valueW);
1987 /* Delete the old external fonts key */
1988 RegCloseKey(external_key);
1989 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1991 end:
1992 if(win9x_key) RegCloseKey(win9x_key);
1993 if(winnt_key) RegCloseKey(winnt_key);
1996 /*************************************************************
1997 * WineEngAddFontResourceEx
2000 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2002 INT ret = 0;
2003 if (ft_handle) /* do it only if we have freetype up and running */
2005 char *unixname;
2007 if(flags)
2008 FIXME("Ignoring flags %x\n", flags);
2010 if((unixname = wine_get_unix_file_name(file)))
2012 EnterCriticalSection( &freetype_cs );
2013 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2014 LeaveCriticalSection( &freetype_cs );
2015 HeapFree(GetProcessHeap(), 0, unixname);
2017 if (!ret && !strchrW(file, '\\')) {
2018 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2019 ret = load_font_from_winfonts_dir(file);
2020 if (!ret) {
2021 /* Try in datadir/fonts (or builddir/fonts),
2022 * needed for Magic the Gathering Online
2024 ret = load_font_from_data_dir(file);
2028 return ret;
2031 /*************************************************************
2032 * WineEngAddFontMemResourceEx
2035 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2037 if (ft_handle) /* do it only if we have freetype up and running */
2039 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2041 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2042 memcpy(pFontCopy, pbFont, cbFont);
2044 EnterCriticalSection( &freetype_cs );
2045 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2046 LeaveCriticalSection( &freetype_cs );
2048 if (*pcFonts == 0)
2050 TRACE("AddFontToList failed\n");
2051 HeapFree(GetProcessHeap(), 0, pFontCopy);
2052 return NULL;
2054 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2055 * For now return something unique but quite random
2057 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2058 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2061 *pcFonts = 0;
2062 return 0;
2065 /*************************************************************
2066 * WineEngRemoveFontResourceEx
2069 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2071 FIXME(":stub\n");
2072 return TRUE;
2075 static const struct nls_update_font_list
2077 UINT ansi_cp, oem_cp;
2078 const char *oem, *fixed, *system;
2079 const char *courier, *serif, *small, *sserif;
2080 /* these are for font substitute */
2081 const char *shelldlg, *tmsrmn;
2082 } nls_update_font_list[] =
2084 /* Latin 1 (United States) */
2085 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2086 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2087 "Tahoma","Times New Roman",
2089 /* Latin 1 (Multilingual) */
2090 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2091 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2092 "Tahoma","Times New Roman", /* FIXME unverified */
2094 /* Eastern Europe */
2095 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2096 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2097 "Tahoma","Times New Roman", /* FIXME unverified */
2099 /* Cyrillic */
2100 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2101 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2102 "Tahoma","Times New Roman", /* FIXME unverified */
2104 /* Greek */
2105 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2106 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2107 "Tahoma","Times New Roman", /* FIXME unverified */
2109 /* Turkish */
2110 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2111 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2112 "Tahoma","Times New Roman", /* FIXME unverified */
2114 /* Hebrew */
2115 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2116 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2117 "Tahoma","Times New Roman", /* FIXME unverified */
2119 /* Arabic */
2120 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2121 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2122 "Tahoma","Times New Roman", /* FIXME unverified */
2124 /* Baltic */
2125 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2126 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2127 "Tahoma","Times New Roman", /* FIXME unverified */
2129 /* Vietnamese */
2130 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2131 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2132 "Tahoma","Times New Roman", /* FIXME unverified */
2134 /* Thai */
2135 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2136 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2137 "Tahoma","Times New Roman", /* FIXME unverified */
2139 /* Japanese */
2140 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2141 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2142 "MS UI Gothic","MS Serif",
2144 /* Chinese Simplified */
2145 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2146 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2147 "Tahoma", "Times New Roman", /* FIXME unverified */
2149 /* Korean */
2150 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2151 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2152 "Gulim", "Batang",
2154 /* Chinese Traditional */
2155 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2156 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2157 "PMingLiU", "MingLiU",
2161 static inline HKEY create_fonts_NT_registry_key(void)
2163 HKEY hkey = 0;
2165 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2166 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2167 return hkey;
2170 static inline HKEY create_fonts_9x_registry_key(void)
2172 HKEY hkey = 0;
2174 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2175 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2176 return hkey;
2179 static inline HKEY create_config_fonts_registry_key(void)
2181 HKEY hkey = 0;
2183 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2184 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2185 return hkey;
2188 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2190 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2191 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2192 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2193 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2196 static void update_font_info(void)
2198 char buf[40], cpbuf[40];
2199 DWORD len, type;
2200 HKEY hkey = 0;
2201 UINT i, ansi_cp = 0, oem_cp = 0;
2203 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2204 return;
2206 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2207 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2208 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2209 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2210 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2212 /* Setup DefaultFallback usage */
2213 if (ansi_cp == 932)
2214 use_default_fallback = TRUE;
2216 len = sizeof(buf);
2217 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2219 if (!strcmp( buf, cpbuf )) /* already set correctly */
2221 RegCloseKey(hkey);
2222 return;
2224 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2226 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2228 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2229 RegCloseKey(hkey);
2231 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2233 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2234 nls_update_font_list[i].oem_cp == oem_cp)
2236 HKEY hkey;
2238 hkey = create_config_fonts_registry_key();
2239 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2240 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2241 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2242 RegCloseKey(hkey);
2244 hkey = create_fonts_NT_registry_key();
2245 add_font_list(hkey, &nls_update_font_list[i]);
2246 RegCloseKey(hkey);
2248 hkey = create_fonts_9x_registry_key();
2249 add_font_list(hkey, &nls_update_font_list[i]);
2250 RegCloseKey(hkey);
2252 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2254 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2255 strlen(nls_update_font_list[i].shelldlg)+1);
2256 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2257 strlen(nls_update_font_list[i].tmsrmn)+1);
2258 RegCloseKey(hkey);
2260 return;
2263 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2267 static BOOL init_freetype(void)
2269 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2270 if(!ft_handle) {
2271 WINE_MESSAGE(
2272 "Wine cannot find the FreeType font library. To enable Wine to\n"
2273 "use TrueType fonts please install a version of FreeType greater than\n"
2274 "or equal to 2.0.5.\n"
2275 "http://www.freetype.org\n");
2276 return FALSE;
2279 #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;}
2281 LOAD_FUNCPTR(FT_Vector_Unit)
2282 LOAD_FUNCPTR(FT_Done_Face)
2283 LOAD_FUNCPTR(FT_Get_Char_Index)
2284 LOAD_FUNCPTR(FT_Get_Module)
2285 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2286 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2287 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2288 LOAD_FUNCPTR(FT_Init_FreeType)
2289 LOAD_FUNCPTR(FT_Load_Glyph)
2290 LOAD_FUNCPTR(FT_Matrix_Multiply)
2291 LOAD_FUNCPTR(FT_MulFix)
2292 LOAD_FUNCPTR(FT_New_Face)
2293 LOAD_FUNCPTR(FT_New_Memory_Face)
2294 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2295 LOAD_FUNCPTR(FT_Outline_Transform)
2296 LOAD_FUNCPTR(FT_Outline_Translate)
2297 LOAD_FUNCPTR(FT_Select_Charmap)
2298 LOAD_FUNCPTR(FT_Set_Charmap)
2299 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2300 LOAD_FUNCPTR(FT_Vector_Transform)
2302 #undef LOAD_FUNCPTR
2303 /* Don't warn if these ones are missing */
2304 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2305 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2306 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2307 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2308 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2309 #ifdef HAVE_FREETYPE_FTWINFNT_H
2310 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2311 #endif
2312 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2313 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2314 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2315 <= 2.0.3 has FT_Sqrt64 */
2316 goto sym_not_found;
2319 if(pFT_Init_FreeType(&library) != 0) {
2320 ERR("Can't init FreeType library\n");
2321 wine_dlclose(ft_handle, NULL, 0);
2322 ft_handle = NULL;
2323 return FALSE;
2325 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2326 if (pFT_Library_Version)
2327 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2329 if (FT_Version.major<=0)
2331 FT_Version.major=2;
2332 FT_Version.minor=0;
2333 FT_Version.patch=5;
2335 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2336 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2337 ((FT_Version.minor << 8) & 0x00ff00) |
2338 ((FT_Version.patch ) & 0x0000ff);
2340 return TRUE;
2342 sym_not_found:
2343 WINE_MESSAGE(
2344 "Wine cannot find certain functions that it needs inside the FreeType\n"
2345 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2346 "FreeType to at least version 2.0.5.\n"
2347 "http://www.freetype.org\n");
2348 wine_dlclose(ft_handle, NULL, 0);
2349 ft_handle = NULL;
2350 return FALSE;
2353 /*************************************************************
2354 * WineEngInit
2356 * Initialize FreeType library and create a list of available faces
2358 BOOL WineEngInit(void)
2360 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2361 static const WCHAR pathW[] = {'P','a','t','h',0};
2362 HKEY hkey;
2363 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2364 LPVOID data;
2365 WCHAR windowsdir[MAX_PATH];
2366 char *unixname;
2367 HANDLE font_mutex;
2368 const char *data_dir;
2370 TRACE("\n");
2372 /* update locale dependent font info in registry */
2373 update_font_info();
2375 if(!init_freetype()) return FALSE;
2377 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2378 ERR("Failed to create font mutex\n");
2379 return FALSE;
2381 WaitForSingleObject(font_mutex, INFINITE);
2383 delete_external_font_keys();
2385 /* load the system bitmap fonts */
2386 load_system_fonts();
2388 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2389 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2390 strcatW(windowsdir, fontsW);
2391 if((unixname = wine_get_unix_file_name(windowsdir)))
2393 ReadFontDir(unixname, FALSE);
2394 HeapFree(GetProcessHeap(), 0, unixname);
2397 /* load the system truetype fonts */
2398 data_dir = wine_get_data_dir();
2399 if (!data_dir) data_dir = wine_get_build_dir();
2400 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2401 strcpy(unixname, data_dir);
2402 strcat(unixname, "/fonts/");
2403 ReadFontDir(unixname, TRUE);
2404 HeapFree(GetProcessHeap(), 0, unixname);
2407 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2408 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2409 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2410 will skip these. */
2411 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2412 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2413 &hkey) == ERROR_SUCCESS) {
2414 LPWSTR valueW;
2415 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2416 &valuelen, &datalen, NULL, NULL);
2418 valuelen++; /* returned value doesn't include room for '\0' */
2419 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2420 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2421 if (valueW && data)
2423 dlen = datalen * sizeof(WCHAR);
2424 vlen = valuelen;
2425 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2426 &dlen) == ERROR_SUCCESS) {
2427 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2429 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2431 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2432 HeapFree(GetProcessHeap(), 0, unixname);
2435 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2437 WCHAR pathW[MAX_PATH];
2438 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2439 BOOL added = FALSE;
2441 sprintfW(pathW, fmtW, windowsdir, data);
2442 if((unixname = wine_get_unix_file_name(pathW)))
2444 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2445 HeapFree(GetProcessHeap(), 0, unixname);
2447 if (!added)
2448 load_font_from_data_dir(data);
2450 /* reset dlen and vlen */
2451 dlen = datalen;
2452 vlen = valuelen;
2455 HeapFree(GetProcessHeap(), 0, data);
2456 HeapFree(GetProcessHeap(), 0, valueW);
2457 RegCloseKey(hkey);
2460 load_fontconfig_fonts();
2462 /* then look in any directories that we've specified in the config file */
2463 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2464 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2466 DWORD len;
2467 LPWSTR valueW;
2468 LPSTR valueA, ptr;
2470 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2472 len += sizeof(WCHAR);
2473 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2474 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2476 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2477 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2478 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2479 TRACE( "got font path %s\n", debugstr_a(valueA) );
2480 ptr = valueA;
2481 while (ptr)
2483 LPSTR next = strchr( ptr, ':' );
2484 if (next) *next++ = 0;
2485 ReadFontDir( ptr, TRUE );
2486 ptr = next;
2488 HeapFree( GetProcessHeap(), 0, valueA );
2490 HeapFree( GetProcessHeap(), 0, valueW );
2492 RegCloseKey(hkey);
2495 DumpFontList();
2496 LoadSubstList();
2497 DumpSubstList();
2498 LoadReplaceList();
2499 update_reg_entries();
2501 init_system_links();
2503 ReleaseMutex(font_mutex);
2504 return TRUE;
2508 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2510 TT_OS2 *pOS2;
2511 TT_HoriHeader *pHori;
2513 LONG ppem;
2515 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2516 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2518 if(height == 0) height = 16;
2520 /* Calc. height of EM square:
2522 * For +ve lfHeight we have
2523 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2524 * Re-arranging gives:
2525 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2527 * For -ve lfHeight we have
2528 * |lfHeight| = ppem
2529 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2530 * with il = winAscent + winDescent - units_per_em]
2534 if(height > 0) {
2535 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2536 ppem = ft_face->units_per_EM * height /
2537 (pHori->Ascender - pHori->Descender);
2538 else
2539 ppem = ft_face->units_per_EM * height /
2540 (pOS2->usWinAscent + pOS2->usWinDescent);
2542 else
2543 ppem = -height;
2545 return ppem;
2548 static struct font_mapping *map_font_file( const char *name )
2550 struct font_mapping *mapping;
2551 struct stat st;
2552 int fd;
2554 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2555 if (fstat( fd, &st ) == -1) goto error;
2557 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2559 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2561 mapping->refcount++;
2562 close( fd );
2563 return mapping;
2566 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2567 goto error;
2569 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2570 close( fd );
2572 if (mapping->data == MAP_FAILED)
2574 HeapFree( GetProcessHeap(), 0, mapping );
2575 return NULL;
2577 mapping->refcount = 1;
2578 mapping->dev = st.st_dev;
2579 mapping->ino = st.st_ino;
2580 mapping->size = st.st_size;
2581 list_add_tail( &mappings_list, &mapping->entry );
2582 return mapping;
2584 error:
2585 close( fd );
2586 return NULL;
2589 static void unmap_font_file( struct font_mapping *mapping )
2591 if (!--mapping->refcount)
2593 list_remove( &mapping->entry );
2594 munmap( mapping->data, mapping->size );
2595 HeapFree( GetProcessHeap(), 0, mapping );
2599 static LONG load_VDMX(GdiFont*, LONG);
2601 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2603 FT_Error err;
2604 FT_Face ft_face;
2605 void *data_ptr;
2606 DWORD data_size;
2608 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2610 if (face->file)
2612 if (!(font->mapping = map_font_file( face->file )))
2614 WARN("failed to map %s\n", debugstr_a(face->file));
2615 return 0;
2617 data_ptr = font->mapping->data;
2618 data_size = font->mapping->size;
2620 else
2622 data_ptr = face->font_data_ptr;
2623 data_size = face->font_data_size;
2626 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2627 if(err) {
2628 ERR("FT_New_Face rets %d\n", err);
2629 return 0;
2632 /* set it here, as load_VDMX needs it */
2633 font->ft_face = ft_face;
2635 if(FT_IS_SCALABLE(ft_face)) {
2636 /* load the VDMX table if we have one */
2637 font->ppem = load_VDMX(font, height);
2638 if(font->ppem == 0)
2639 font->ppem = calc_ppem_for_height(ft_face, height);
2641 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2642 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2643 } else {
2644 font->ppem = height;
2645 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2646 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2648 return ft_face;
2652 static int get_nearest_charset(Face *face, int *cp)
2654 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2655 a single face with the requested charset. The idea is to check if
2656 the selected font supports the current ANSI codepage, if it does
2657 return the corresponding charset, else return the first charset */
2659 CHARSETINFO csi;
2660 int acp = GetACP(), i;
2661 DWORD fs0;
2663 *cp = acp;
2664 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2665 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2666 return csi.ciCharset;
2668 for(i = 0; i < 32; i++) {
2669 fs0 = 1L << i;
2670 if(face->fs.fsCsb[0] & fs0) {
2671 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2672 *cp = csi.ciACP;
2673 return csi.ciCharset;
2675 else
2676 FIXME("TCI failing on %x\n", fs0);
2680 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2681 face->fs.fsCsb[0], face->file);
2682 *cp = acp;
2683 return DEFAULT_CHARSET;
2686 static GdiFont *alloc_font(void)
2688 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2689 ret->gmsize = 1;
2690 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2691 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2692 ret->potm = NULL;
2693 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2694 ret->total_kern_pairs = (DWORD)-1;
2695 ret->kern_pairs = NULL;
2696 list_init(&ret->hfontlist);
2697 list_init(&ret->child_fonts);
2698 return ret;
2701 static void free_font(GdiFont *font)
2703 struct list *cursor, *cursor2;
2704 int i;
2706 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2708 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2709 struct list *first_hfont;
2710 HFONTLIST *hfontlist;
2711 list_remove(cursor);
2712 if(child->font)
2714 first_hfont = list_head(&child->font->hfontlist);
2715 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2716 DeleteObject(hfontlist->hfont);
2717 HeapFree(GetProcessHeap(), 0, hfontlist);
2718 free_font(child->font);
2720 HeapFree(GetProcessHeap(), 0, child);
2723 if (font->ft_face) pFT_Done_Face(font->ft_face);
2724 if (font->mapping) unmap_font_file( font->mapping );
2725 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2726 HeapFree(GetProcessHeap(), 0, font->potm);
2727 HeapFree(GetProcessHeap(), 0, font->name);
2728 for (i = 0; i < font->gmsize; i++)
2729 HeapFree(GetProcessHeap(),0,font->gm[i]);
2730 HeapFree(GetProcessHeap(), 0, font->gm);
2731 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2732 HeapFree(GetProcessHeap(), 0, font);
2736 /*************************************************************
2737 * load_VDMX
2739 * load the vdmx entry for the specified height
2742 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2743 ( ( (FT_ULong)_x4 << 24 ) | \
2744 ( (FT_ULong)_x3 << 16 ) | \
2745 ( (FT_ULong)_x2 << 8 ) | \
2746 (FT_ULong)_x1 )
2748 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2750 typedef struct {
2751 BYTE bCharSet;
2752 BYTE xRatio;
2753 BYTE yStartRatio;
2754 BYTE yEndRatio;
2755 } Ratios;
2757 typedef struct {
2758 WORD recs;
2759 BYTE startsz;
2760 BYTE endsz;
2761 } VDMX_group;
2763 static LONG load_VDMX(GdiFont *font, LONG height)
2765 WORD hdr[3], tmp;
2766 VDMX_group group;
2767 BYTE devXRatio, devYRatio;
2768 USHORT numRecs, numRatios;
2769 DWORD result, offset = -1;
2770 LONG ppem = 0;
2771 int i;
2773 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2775 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2776 return ppem;
2778 /* FIXME: need the real device aspect ratio */
2779 devXRatio = 1;
2780 devYRatio = 1;
2782 numRecs = GET_BE_WORD(hdr[1]);
2783 numRatios = GET_BE_WORD(hdr[2]);
2785 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2786 for(i = 0; i < numRatios; i++) {
2787 Ratios ratio;
2789 offset = (3 * 2) + (i * sizeof(Ratios));
2790 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2791 offset = -1;
2793 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2795 if((ratio.xRatio == 0 &&
2796 ratio.yStartRatio == 0 &&
2797 ratio.yEndRatio == 0) ||
2798 (devXRatio == ratio.xRatio &&
2799 devYRatio >= ratio.yStartRatio &&
2800 devYRatio <= ratio.yEndRatio))
2802 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2803 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2804 offset = GET_BE_WORD(tmp);
2805 break;
2809 if(offset == -1) {
2810 FIXME("No suitable ratio found\n");
2811 return ppem;
2814 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2815 USHORT recs;
2816 BYTE startsz, endsz;
2817 WORD *vTable;
2819 recs = GET_BE_WORD(group.recs);
2820 startsz = group.startsz;
2821 endsz = group.endsz;
2823 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2825 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2826 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2827 if(result == GDI_ERROR) {
2828 FIXME("Failed to retrieve vTable\n");
2829 goto end;
2832 if(height > 0) {
2833 for(i = 0; i < recs; i++) {
2834 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2835 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2836 ppem = GET_BE_WORD(vTable[i * 3]);
2838 if(yMax + -yMin == height) {
2839 font->yMax = yMax;
2840 font->yMin = yMin;
2841 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2842 break;
2844 if(yMax + -yMin > height) {
2845 if(--i < 0) {
2846 ppem = 0;
2847 goto end; /* failed */
2849 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2850 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2851 ppem = GET_BE_WORD(vTable[i * 3]);
2852 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2853 break;
2856 if(!font->yMax) {
2857 ppem = 0;
2858 TRACE("ppem not found for height %d\n", height);
2860 } else {
2861 ppem = -height;
2862 if(ppem < startsz || ppem > endsz)
2863 goto end;
2865 for(i = 0; i < recs; i++) {
2866 USHORT yPelHeight;
2867 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2869 if(yPelHeight > ppem)
2870 break; /* failed */
2872 if(yPelHeight == ppem) {
2873 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2874 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2875 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2876 break;
2880 end:
2881 HeapFree(GetProcessHeap(), 0, vTable);
2884 return ppem;
2887 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2889 if(font->font_desc.hash != fd->hash) return TRUE;
2890 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2891 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2892 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2893 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2896 static void calc_hash(FONT_DESC *pfd)
2898 DWORD hash = 0, *ptr, two_chars;
2899 WORD *pwc;
2900 unsigned int i;
2902 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2903 hash ^= *ptr;
2904 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2905 hash ^= *ptr;
2906 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2907 two_chars = *ptr;
2908 pwc = (WCHAR *)&two_chars;
2909 if(!*pwc) break;
2910 *pwc = toupperW(*pwc);
2911 pwc++;
2912 *pwc = toupperW(*pwc);
2913 hash ^= two_chars;
2914 if(!*pwc) break;
2916 hash ^= !pfd->can_use_bitmap;
2917 pfd->hash = hash;
2918 return;
2921 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2923 GdiFont *ret;
2924 FONT_DESC fd;
2925 HFONTLIST *hflist;
2926 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2928 fd.lf = *plf;
2929 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2930 fd.can_use_bitmap = can_use_bitmap;
2931 calc_hash(&fd);
2933 /* try the in-use list */
2934 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2935 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2936 if(!fontcmp(ret, &fd)) {
2937 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2938 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2939 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2940 if(hflist->hfont == hfont)
2941 return ret;
2943 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2944 hflist->hfont = hfont;
2945 list_add_head(&ret->hfontlist, &hflist->entry);
2946 return ret;
2950 /* then the unused list */
2951 font_elem_ptr = list_head(&unused_gdi_font_list);
2952 while(font_elem_ptr) {
2953 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2954 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2955 if(!fontcmp(ret, &fd)) {
2956 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2957 assert(list_empty(&ret->hfontlist));
2958 TRACE("Found %p in unused list\n", ret);
2959 list_remove(&ret->entry);
2960 list_add_head(&gdi_font_list, &ret->entry);
2961 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2962 hflist->hfont = hfont;
2963 list_add_head(&ret->hfontlist, &hflist->entry);
2964 return ret;
2967 return NULL;
2971 /*************************************************************
2972 * create_child_font_list
2974 static BOOL create_child_font_list(GdiFont *font)
2976 BOOL ret = FALSE;
2977 SYSTEM_LINKS *font_link;
2978 CHILD_FONT *font_link_entry, *new_child;
2980 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2982 if(!strcmpW(font_link->font_name, font->name))
2984 TRACE("found entry in system list\n");
2985 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2987 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2988 new_child->face = font_link_entry->face;
2989 new_child->font = NULL;
2990 list_add_tail(&font->child_fonts, &new_child->entry);
2991 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2993 ret = TRUE;
2994 break;
2998 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
2999 * Sans Serif. This is how asian windows get default fallbacks for fonts
3001 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3002 font->charset != OEM_CHARSET &&
3003 strcmpW(font->name,szDefaultFallbackLink) != 0)
3004 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3006 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3008 TRACE("found entry in default fallback list\n");
3009 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3011 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3012 new_child->face = font_link_entry->face;
3013 new_child->font = NULL;
3014 list_add_tail(&font->child_fonts, &new_child->entry);
3015 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3017 ret = TRUE;
3018 break;
3022 return ret;
3025 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3027 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3029 if (pFT_Set_Charmap)
3031 FT_Int i;
3032 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3034 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3036 for (i = 0; i < ft_face->num_charmaps; i++)
3038 if (ft_face->charmaps[i]->encoding == encoding)
3040 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3041 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3043 switch (ft_face->charmaps[i]->platform_id)
3045 default:
3046 cmap_def = ft_face->charmaps[i];
3047 break;
3048 case 0: /* Apple Unicode */
3049 cmap0 = ft_face->charmaps[i];
3050 break;
3051 case 1: /* Macintosh */
3052 cmap1 = ft_face->charmaps[i];
3053 break;
3054 case 2: /* ISO */
3055 cmap2 = ft_face->charmaps[i];
3056 break;
3057 case 3: /* Microsoft */
3058 cmap3 = ft_face->charmaps[i];
3059 break;
3063 if (cmap3) /* prefer Microsoft cmap table */
3064 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3065 else if (cmap1)
3066 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3067 else if (cmap2)
3068 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3069 else if (cmap0)
3070 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3071 else if (cmap_def)
3072 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3074 return ft_err == FT_Err_Ok;
3077 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3080 /*************************************************************
3081 * WineEngCreateFontInstance
3084 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3086 GdiFont *ret;
3087 Face *face, *best, *best_bitmap;
3088 Family *family, *last_resort_family;
3089 struct list *family_elem_ptr, *face_elem_ptr;
3090 INT height, width = 0;
3091 unsigned int score = 0, new_score;
3092 signed int diff = 0, newdiff;
3093 BOOL bd, it, can_use_bitmap;
3094 LOGFONTW lf;
3095 CHARSETINFO csi;
3096 HFONTLIST *hflist;
3098 EnterCriticalSection( &freetype_cs );
3100 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3102 struct list *first_hfont = list_head(&ret->hfontlist);
3103 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3104 if(hflist->hfont == hfont)
3106 LeaveCriticalSection( &freetype_cs );
3107 return ret;
3111 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3113 LeaveCriticalSection( &freetype_cs );
3114 return NULL;
3116 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3118 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3119 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3120 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3121 lf.lfEscapement);
3123 /* check the cache first */
3124 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3125 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3126 LeaveCriticalSection( &freetype_cs );
3127 return ret;
3130 TRACE("not in cache\n");
3131 if(list_empty(&font_list)) /* No fonts installed */
3133 TRACE("No fonts installed\n");
3134 LeaveCriticalSection( &freetype_cs );
3135 return NULL;
3137 if(!have_installed_roman_font)
3139 TRACE("No roman font installed\n");
3140 LeaveCriticalSection( &freetype_cs );
3141 return NULL;
3144 ret = alloc_font();
3146 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3147 ret->font_desc.lf = lf;
3148 ret->font_desc.can_use_bitmap = can_use_bitmap;
3149 calc_hash(&ret->font_desc);
3150 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3151 hflist->hfont = hfont;
3152 list_add_head(&ret->hfontlist, &hflist->entry);
3155 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3156 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3157 original value lfCharSet. Note this is a special case for
3158 Symbol and doesn't happen at least for "Wingdings*" */
3160 if(!strcmpiW(lf.lfFaceName, SymbolW))
3161 lf.lfCharSet = SYMBOL_CHARSET;
3163 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3164 switch(lf.lfCharSet) {
3165 case DEFAULT_CHARSET:
3166 csi.fs.fsCsb[0] = 0;
3167 break;
3168 default:
3169 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3170 csi.fs.fsCsb[0] = 0;
3171 break;
3175 family = NULL;
3176 if(lf.lfFaceName[0] != '\0') {
3177 FontSubst *psub;
3178 SYSTEM_LINKS *font_link;
3179 CHILD_FONT *font_link_entry;
3180 LPWSTR FaceName = lf.lfFaceName;
3183 * Check for a leading '@' this signals that the font is being
3184 * requested in tategaki mode (vertical writing subtitution) but
3185 * does not affect the fontface that is to be selected.
3187 if (lf.lfFaceName[0]=='@')
3188 FaceName = &lf.lfFaceName[1];
3190 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3192 if(psub) {
3193 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3194 debugstr_w(psub->to.name));
3195 strcpyW(FaceName, psub->to.name);
3198 /* We want a match on name and charset or just name if
3199 charset was DEFAULT_CHARSET. If the latter then
3200 we fixup the returned charset later in get_nearest_charset
3201 where we'll either use the charset of the current ansi codepage
3202 or if that's unavailable the first charset that the font supports.
3204 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3205 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3206 if(!strcmpiW(family->FamilyName, FaceName)) {
3207 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3208 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3209 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3210 if(face->scalable || can_use_bitmap)
3211 goto found;
3217 * Try check the SystemLink list first for a replacement font.
3218 * We may find good replacements there.
3220 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3222 if(!strcmpiW(font_link->font_name, FaceName))
3224 TRACE("found entry in system list\n");
3225 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3227 face = font_link_entry->face;
3228 family = face->family;
3229 if(csi.fs.fsCsb[0] &
3230 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3232 if(face->scalable || can_use_bitmap)
3233 goto found;
3240 /* If requested charset was DEFAULT_CHARSET then try using charset
3241 corresponding to the current ansi codepage */
3242 if(!csi.fs.fsCsb[0]) {
3243 INT acp = GetACP();
3244 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3245 FIXME("TCI failed on codepage %d\n", acp);
3246 csi.fs.fsCsb[0] = 0;
3247 } else
3248 lf.lfCharSet = csi.ciCharset;
3251 /* Face families are in the top 4 bits of lfPitchAndFamily,
3252 so mask with 0xF0 before testing */
3254 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3255 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3256 strcpyW(lf.lfFaceName, defFixed);
3257 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3258 strcpyW(lf.lfFaceName, defSerif);
3259 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3260 strcpyW(lf.lfFaceName, defSans);
3261 else
3262 strcpyW(lf.lfFaceName, defSans);
3263 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3264 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3265 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3266 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3267 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3268 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3269 if(face->scalable || can_use_bitmap)
3270 goto found;
3275 last_resort_family = NULL;
3276 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3277 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3278 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3279 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3280 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3281 if(face->scalable)
3282 goto found;
3283 if(can_use_bitmap && !last_resort_family)
3284 last_resort_family = family;
3289 if(last_resort_family) {
3290 family = last_resort_family;
3291 csi.fs.fsCsb[0] = 0;
3292 goto found;
3295 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3296 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3297 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3298 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3299 if(face->scalable) {
3300 csi.fs.fsCsb[0] = 0;
3301 WARN("just using first face for now\n");
3302 goto found;
3304 if(can_use_bitmap && !last_resort_family)
3305 last_resort_family = family;
3308 if(!last_resort_family) {
3309 FIXME("can't find a single appropriate font - bailing\n");
3310 free_font(ret);
3311 LeaveCriticalSection( &freetype_cs );
3312 return NULL;
3315 WARN("could only find a bitmap font - this will probably look awful!\n");
3316 family = last_resort_family;
3317 csi.fs.fsCsb[0] = 0;
3319 found:
3320 it = lf.lfItalic ? 1 : 0;
3321 bd = lf.lfWeight > 550 ? 1 : 0;
3323 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3324 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3326 face = best = best_bitmap = NULL;
3327 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3329 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3331 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3332 if(!best || new_score <= score)
3334 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3335 face->Italic, face->Bold, it, bd);
3336 score = new_score;
3337 best = face;
3338 if(best->scalable && score == 0) break;
3339 if(!best->scalable)
3341 if(height > 0)
3342 newdiff = height - (signed int)(best->size.height);
3343 else
3344 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3345 if(!best_bitmap || new_score < score ||
3346 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3348 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3349 diff = newdiff;
3350 best_bitmap = best;
3351 if(score == 0 && diff == 0) break;
3357 if(best)
3358 face = best->scalable ? best : best_bitmap;
3359 ret->fake_italic = (it && !face->Italic);
3360 ret->fake_bold = (bd && !face->Bold);
3362 ret->fs = face->fs;
3364 if(csi.fs.fsCsb[0]) {
3365 ret->charset = lf.lfCharSet;
3366 ret->codepage = csi.ciACP;
3368 else
3369 ret->charset = get_nearest_charset(face, &ret->codepage);
3371 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3372 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3374 ret->aveWidth = abs(lf.lfWidth);
3376 if(!face->scalable) {
3377 /* Windows uses integer scaling factors for bitmap fonts */
3378 INT scale, scaled_height;
3380 if (height != 0) height = diff;
3381 else height = 0;
3382 height += face->size.height;
3384 scale = (height + face->size.height - 1) / face->size.height;
3385 scaled_height = scale * face->size.height;
3386 /* XP allows not more than 10% deviation */
3387 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3388 ret->scale_y = scale;
3390 width = face->size.x_ppem >> 6;
3391 height = face->size.y_ppem >> 6;
3393 else
3394 ret->scale_y = 1.0;
3395 TRACE("font scale y: %f\n", ret->scale_y);
3397 ret->ft_face = OpenFontFace(ret, face, width, height);
3399 if (!ret->ft_face)
3401 free_font( ret );
3402 LeaveCriticalSection( &freetype_cs );
3403 return 0;
3406 ret->ntmFlags = face->ntmFlags;
3408 if (ret->charset == SYMBOL_CHARSET &&
3409 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3410 /* No ops */
3412 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3413 /* No ops */
3415 else {
3416 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3419 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3420 ret->name = strdupW(family->FamilyName);
3421 ret->underline = lf.lfUnderline ? 0xff : 0;
3422 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3423 create_child_font_list(ret);
3425 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3427 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3428 if (length != GDI_ERROR)
3430 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3431 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3432 TRACE("Loaded GSUB table of %i bytes\n",length);
3436 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3438 list_add_head(&gdi_font_list, &ret->entry);
3439 LeaveCriticalSection( &freetype_cs );
3440 return ret;
3443 static void dump_gdi_font_list(void)
3445 GdiFont *gdiFont;
3446 struct list *elem_ptr;
3448 TRACE("---------- gdiFont Cache ----------\n");
3449 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3450 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3451 TRACE("gdiFont=%p %s %d\n",
3452 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3455 TRACE("---------- Unused gdiFont Cache ----------\n");
3456 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3457 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3458 TRACE("gdiFont=%p %s %d\n",
3459 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3463 /*************************************************************
3464 * WineEngDestroyFontInstance
3466 * free the gdiFont associated with this handle
3469 BOOL WineEngDestroyFontInstance(HFONT handle)
3471 GdiFont *gdiFont;
3472 HFONTLIST *hflist;
3473 BOOL ret = FALSE;
3474 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3475 int i = 0;
3477 EnterCriticalSection( &freetype_cs );
3479 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3481 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3482 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3483 if(hflist->hfont == handle)
3485 TRACE("removing child font %p from child list\n", gdiFont);
3486 list_remove(&gdiFont->entry);
3487 LeaveCriticalSection( &freetype_cs );
3488 return TRUE;
3492 TRACE("destroying hfont=%p\n", handle);
3493 if(TRACE_ON(font))
3494 dump_gdi_font_list();
3496 font_elem_ptr = list_head(&gdi_font_list);
3497 while(font_elem_ptr) {
3498 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3499 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3501 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3502 while(hfontlist_elem_ptr) {
3503 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3504 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3505 if(hflist->hfont == handle) {
3506 list_remove(&hflist->entry);
3507 HeapFree(GetProcessHeap(), 0, hflist);
3508 ret = TRUE;
3511 if(list_empty(&gdiFont->hfontlist)) {
3512 TRACE("Moving to Unused list\n");
3513 list_remove(&gdiFont->entry);
3514 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3519 font_elem_ptr = list_head(&unused_gdi_font_list);
3520 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3521 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3522 while(font_elem_ptr) {
3523 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3524 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3525 TRACE("freeing %p\n", gdiFont);
3526 list_remove(&gdiFont->entry);
3527 free_font(gdiFont);
3529 LeaveCriticalSection( &freetype_cs );
3530 return ret;
3533 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3534 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3536 GdiFont *font;
3537 LONG width, height;
3539 if (face->cached_enum_data)
3541 TRACE("Cached\n");
3542 *pelf = face->cached_enum_data->elf;
3543 *pntm = face->cached_enum_data->ntm;
3544 *ptype = face->cached_enum_data->type;
3545 return;
3548 font = alloc_font();
3550 if(face->scalable) {
3551 height = 100;
3552 width = 0;
3553 } else {
3554 height = face->size.y_ppem >> 6;
3555 width = face->size.x_ppem >> 6;
3557 font->scale_y = 1.0;
3559 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3561 free_font(font);
3562 return;
3565 font->name = strdupW(face->family->FamilyName);
3566 font->ntmFlags = face->ntmFlags;
3568 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3570 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3572 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3574 lstrcpynW(pelf->elfLogFont.lfFaceName,
3575 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3576 LF_FACESIZE);
3577 lstrcpynW(pelf->elfFullName,
3578 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3579 LF_FULLFACESIZE);
3580 lstrcpynW(pelf->elfStyle,
3581 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3582 LF_FACESIZE);
3584 else
3586 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3588 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3590 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3591 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3592 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3595 pntm->ntmTm.ntmFlags = face->ntmFlags;
3596 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3597 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3598 pntm->ntmFontSig = face->fs;
3600 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3602 pelf->elfLogFont.lfEscapement = 0;
3603 pelf->elfLogFont.lfOrientation = 0;
3604 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3605 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3606 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3607 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3608 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3609 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3610 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3611 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3612 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3613 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3614 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3616 *ptype = 0;
3617 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3618 *ptype |= TRUETYPE_FONTTYPE;
3619 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3620 *ptype |= DEVICE_FONTTYPE;
3621 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3622 *ptype |= RASTER_FONTTYPE;
3624 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3625 if (face->cached_enum_data)
3627 face->cached_enum_data->elf = *pelf;
3628 face->cached_enum_data->ntm = *pntm;
3629 face->cached_enum_data->type = *ptype;
3632 free_font(font);
3635 /*************************************************************
3636 * WineEngEnumFonts
3639 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3641 Family *family;
3642 Face *face;
3643 struct list *family_elem_ptr, *face_elem_ptr;
3644 ENUMLOGFONTEXW elf;
3645 NEWTEXTMETRICEXW ntm;
3646 DWORD type;
3647 FONTSIGNATURE fs;
3648 CHARSETINFO csi;
3649 LOGFONTW lf;
3650 int i;
3652 if (!plf)
3654 lf.lfCharSet = DEFAULT_CHARSET;
3655 lf.lfPitchAndFamily = 0;
3656 lf.lfFaceName[0] = 0;
3657 plf = &lf;
3660 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3662 EnterCriticalSection( &freetype_cs );
3663 if(plf->lfFaceName[0]) {
3664 FontSubst *psub;
3665 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3667 if(psub) {
3668 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3669 debugstr_w(psub->to.name));
3670 lf = *plf;
3671 strcpyW(lf.lfFaceName, psub->to.name);
3672 plf = &lf;
3675 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3676 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3677 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3678 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3679 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3680 GetEnumStructs(face, &elf, &ntm, &type);
3681 for(i = 0; i < 32; i++) {
3682 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3683 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3684 strcpyW(elf.elfScript, OEM_DOSW);
3685 i = 32; /* break out of loop */
3686 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3687 continue;
3688 else {
3689 fs.fsCsb[0] = 1L << i;
3690 fs.fsCsb[1] = 0;
3691 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3692 TCI_SRCFONTSIG))
3693 csi.ciCharset = DEFAULT_CHARSET;
3694 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3695 if(csi.ciCharset != DEFAULT_CHARSET) {
3696 elf.elfLogFont.lfCharSet =
3697 ntm.ntmTm.tmCharSet = csi.ciCharset;
3698 if(ElfScriptsW[i])
3699 strcpyW(elf.elfScript, ElfScriptsW[i]);
3700 else
3701 FIXME("Unknown elfscript for bit %d\n", i);
3704 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3705 debugstr_w(elf.elfLogFont.lfFaceName),
3706 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3707 csi.ciCharset, type, debugstr_w(elf.elfScript),
3708 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3709 ntm.ntmTm.ntmFlags);
3710 /* release section before callback (FIXME) */
3711 LeaveCriticalSection( &freetype_cs );
3712 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3713 EnterCriticalSection( &freetype_cs );
3718 } else {
3719 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3720 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3721 face_elem_ptr = list_head(&family->faces);
3722 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3723 GetEnumStructs(face, &elf, &ntm, &type);
3724 for(i = 0; i < 32; i++) {
3725 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3726 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3727 strcpyW(elf.elfScript, OEM_DOSW);
3728 i = 32; /* break out of loop */
3729 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3730 continue;
3731 else {
3732 fs.fsCsb[0] = 1L << i;
3733 fs.fsCsb[1] = 0;
3734 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3735 TCI_SRCFONTSIG))
3736 csi.ciCharset = DEFAULT_CHARSET;
3737 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3738 if(csi.ciCharset != DEFAULT_CHARSET) {
3739 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3740 csi.ciCharset;
3741 if(ElfScriptsW[i])
3742 strcpyW(elf.elfScript, ElfScriptsW[i]);
3743 else
3744 FIXME("Unknown elfscript for bit %d\n", i);
3747 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3748 debugstr_w(elf.elfLogFont.lfFaceName),
3749 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3750 csi.ciCharset, type, debugstr_w(elf.elfScript),
3751 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3752 ntm.ntmTm.ntmFlags);
3753 /* release section before callback (FIXME) */
3754 LeaveCriticalSection( &freetype_cs );
3755 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3756 EnterCriticalSection( &freetype_cs );
3760 LeaveCriticalSection( &freetype_cs );
3761 return 1;
3764 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3766 pt->x.value = vec->x >> 6;
3767 pt->x.fract = (vec->x & 0x3f) << 10;
3768 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3769 pt->y.value = vec->y >> 6;
3770 pt->y.fract = (vec->y & 0x3f) << 10;
3771 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3772 return;
3775 /***************************************************
3776 * According to the MSDN documentation on WideCharToMultiByte,
3777 * certain codepages cannot set the default_used parameter.
3778 * This returns TRUE if the codepage can set that parameter, false else
3779 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3781 static BOOL codepage_sets_default_used(UINT codepage)
3783 switch (codepage)
3785 case CP_UTF7:
3786 case CP_UTF8:
3787 case CP_SYMBOL:
3788 return FALSE;
3789 default:
3790 return TRUE;
3795 * GSUB Table handling functions
3798 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3800 const GSUB_CoverageFormat1* cf1;
3802 cf1 = (GSUB_CoverageFormat1*)table;
3804 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3806 int count = GET_BE_WORD(cf1->GlyphCount);
3807 int i;
3808 TRACE("Coverage Format 1, %i glyphs\n",count);
3809 for (i = 0; i < count; i++)
3810 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3811 return i;
3812 return -1;
3814 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3816 const GSUB_CoverageFormat2* cf2;
3817 int i;
3818 int count;
3819 cf2 = (GSUB_CoverageFormat2*)cf1;
3821 count = GET_BE_WORD(cf2->RangeCount);
3822 TRACE("Coverage Format 2, %i ranges\n",count);
3823 for (i = 0; i < count; i++)
3825 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3826 return -1;
3827 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3828 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3830 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3831 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3833 return -1;
3836 else
3837 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3839 return -1;
3842 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3844 const GSUB_ScriptList *script;
3845 const GSUB_Script *deflt = NULL;
3846 int i;
3847 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3849 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3850 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3852 const GSUB_Script *scr;
3853 int offset;
3855 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3856 scr = (GSUB_Script*)((LPBYTE)script + offset);
3858 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3859 return scr;
3860 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3861 deflt = scr;
3863 return deflt;
3866 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3868 int i;
3869 int offset;
3870 const GSUB_LangSys *Lang;
3872 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3874 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3876 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3877 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3879 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3880 return Lang;
3882 offset = GET_BE_WORD(script->DefaultLangSys);
3883 if (offset)
3885 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3886 return Lang;
3888 return NULL;
3891 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3893 int i;
3894 const GSUB_FeatureList *feature;
3895 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3897 TRACE("%i features \n",GET_BE_WORD(lang->FeatureCount));
3898 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3900 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3901 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3903 const GSUB_Feature *feat;
3904 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3905 return feat;
3908 return NULL;
3911 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3913 int i;
3914 int offset;
3915 const GSUB_LookupList *lookup;
3916 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3918 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3919 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3921 const GSUB_LookupTable *look;
3922 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3923 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3924 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3925 if (GET_BE_WORD(look->LookupType) != 1)
3926 FIXME("We only handle SubType 1\n");
3927 else
3929 int j;
3931 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3933 const GSUB_SingleSubstFormat1 *ssf1;
3934 offset = GET_BE_WORD(look->SubTable[j]);
3935 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3936 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3938 int offset = GET_BE_WORD(ssf1->Coverage);
3939 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
3940 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
3942 TRACE(" Glyph 0x%x ->",glyph);
3943 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
3944 TRACE(" 0x%x\n",glyph);
3947 else
3949 const GSUB_SingleSubstFormat2 *ssf2;
3950 INT index;
3951 INT offset;
3953 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
3954 offset = GET_BE_WORD(ssf1->Coverage);
3955 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
3956 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
3957 TRACE(" Coverage index %i\n",index);
3958 if (index != -1)
3960 TRACE(" Glyph is 0x%x ->",glyph);
3961 glyph = GET_BE_WORD(ssf2->Substitute[index]);
3962 TRACE("0x%x\n",glyph);
3968 return glyph;
3971 static const char* get_opentype_script(const GdiFont *font)
3974 * I am not sure if this is the correct way to generate our script tag
3977 switch (font->charset)
3979 case ANSI_CHARSET: return "latn";
3980 case BALTIC_CHARSET: return "latn"; /* ?? */
3981 case CHINESEBIG5_CHARSET: return "hani";
3982 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
3983 case GB2312_CHARSET: return "hani";
3984 case GREEK_CHARSET: return "grek";
3985 case HANGUL_CHARSET: return "hang";
3986 case RUSSIAN_CHARSET: return "cyrl";
3987 case SHIFTJIS_CHARSET: return "kana";
3988 case TURKISH_CHARSET: return "latn"; /* ?? */
3989 case VIETNAMESE_CHARSET: return "latn";
3990 case JOHAB_CHARSET: return "latn"; /* ?? */
3991 case ARABIC_CHARSET: return "arab";
3992 case HEBREW_CHARSET: return "hebr";
3993 case THAI_CHARSET: return "thai";
3994 default: return "latn";
3998 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4000 const GSUB_Header *header;
4001 const GSUB_Script *script;
4002 const GSUB_LangSys *language;
4003 const GSUB_Feature *feature;
4005 if (!font->GSUB_Table)
4006 return glyph;
4008 header = font->GSUB_Table;
4010 script = GSUB_get_script_table(header, get_opentype_script(font));
4011 if (!script)
4013 TRACE("Script not found\n");
4014 return glyph;
4016 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4017 if (!language)
4019 TRACE("Language not found\n");
4020 return glyph;
4022 feature = GSUB_get_feature(header, language, "vrt2");
4023 if (!feature)
4024 feature = GSUB_get_feature(header, language, "vert");
4025 if (!feature)
4027 TRACE("vrt2/vert feature not found\n");
4028 return glyph;
4030 return GSUB_apply_feature(header, feature, glyph);
4033 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4035 FT_UInt glyphId;
4037 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4038 WCHAR wc = (WCHAR)glyph;
4039 BOOL default_used;
4040 BOOL *default_used_pointer;
4041 FT_UInt ret;
4042 char buf;
4043 default_used_pointer = NULL;
4044 default_used = FALSE;
4045 if (codepage_sets_default_used(font->codepage))
4046 default_used_pointer = &default_used;
4047 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4048 ret = 0;
4049 else
4050 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4051 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4052 return get_GSUB_vert_glyph(font,ret);
4055 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
4056 glyph = glyph + 0xf000;
4057 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4058 return get_GSUB_vert_glyph(font,glyphId);
4061 /*************************************************************
4062 * WineEngGetGlyphIndices
4064 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
4066 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4067 LPWORD pgi, DWORD flags)
4069 int i;
4070 WCHAR default_char = 0;
4071 TEXTMETRICW textm;
4073 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
4075 for(i = 0; i < count; i++)
4077 pgi[i] = get_glyph_index(font, lpstr[i]);
4078 if (pgi[i] == 0)
4080 if (!default_char)
4082 WineEngGetTextMetrics(font, &textm);
4083 default_char = textm.tmDefaultChar;
4085 pgi[i] = default_char;
4088 return count;
4091 /*************************************************************
4092 * WineEngGetGlyphOutline
4094 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4095 * except that the first parameter is the HWINEENGFONT of the font in
4096 * question rather than an HDC.
4099 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4100 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4101 const MAT2* lpmat)
4103 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4104 FT_Face ft_face = incoming_font->ft_face;
4105 GdiFont *font = incoming_font;
4106 FT_UInt glyph_index;
4107 DWORD width, height, pitch, needed = 0;
4108 FT_Bitmap ft_bitmap;
4109 FT_Error err;
4110 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4111 FT_Angle angle = 0;
4112 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4113 float widthRatio = 1.0;
4114 FT_Matrix transMat = identityMat;
4115 BOOL needsTransform = FALSE;
4116 BOOL tategaki = (font->GSUB_Table != NULL);
4117 UINT original_index;
4120 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4121 buflen, buf, lpmat);
4123 EnterCriticalSection( &freetype_cs );
4125 if(format & GGO_GLYPH_INDEX) {
4126 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4127 original_index = glyph;
4128 format &= ~GGO_GLYPH_INDEX;
4129 } else {
4130 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4131 ft_face = font->ft_face;
4132 original_index = glyph_index;
4135 /* tategaki never appears to happen to lower glyph index */
4136 if (glyph_index < TATEGAKI_LOWER_BOUND )
4137 tategaki = FALSE;
4139 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4140 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4141 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4142 font->gmsize * sizeof(GM*));
4143 } else {
4144 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4145 *lpgm = FONT_GM(font,original_index)->gm;
4146 LeaveCriticalSection( &freetype_cs );
4147 return 1; /* FIXME */
4151 if (!font->gm[original_index / GM_BLOCK_SIZE])
4152 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4154 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4155 load_flags |= FT_LOAD_NO_BITMAP;
4157 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4159 if(err) {
4160 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4161 LeaveCriticalSection( &freetype_cs );
4162 return GDI_ERROR;
4165 /* Scaling factor */
4166 if (font->aveWidth && font->potm)
4168 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4169 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4171 else
4172 widthRatio = font->scale_y;
4174 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4175 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4177 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4178 lsb = left >> 6;
4179 bbx = (right - left) >> 6;
4181 /* Scaling transform */
4182 if(font->aveWidth) {
4183 FT_Matrix scaleMat;
4184 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4185 scaleMat.xy = 0;
4186 scaleMat.yx = 0;
4187 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4189 pFT_Matrix_Multiply(&scaleMat, &transMat);
4190 needsTransform = TRUE;
4193 /* Slant transform */
4194 if (font->fake_italic) {
4195 FT_Matrix slantMat;
4197 slantMat.xx = (1 << 16);
4198 slantMat.xy = ((1 << 16) >> 2);
4199 slantMat.yx = 0;
4200 slantMat.yy = (1 << 16);
4201 pFT_Matrix_Multiply(&slantMat, &transMat);
4202 needsTransform = TRUE;
4205 /* Rotation transform */
4206 if(font->orientation && !tategaki) {
4207 FT_Matrix rotationMat;
4208 FT_Vector vecAngle;
4209 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4210 pFT_Vector_Unit(&vecAngle, angle);
4211 rotationMat.xx = vecAngle.x;
4212 rotationMat.xy = -vecAngle.y;
4213 rotationMat.yx = -rotationMat.xy;
4214 rotationMat.yy = rotationMat.xx;
4216 pFT_Matrix_Multiply(&rotationMat, &transMat);
4217 needsTransform = TRUE;
4220 /* Extra transformation specified by caller */
4221 if (lpmat) {
4222 FT_Matrix extraMat;
4223 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4224 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4225 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4226 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4227 pFT_Matrix_Multiply(&extraMat, &transMat);
4228 needsTransform = TRUE;
4231 if(!needsTransform) {
4232 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4233 bottom = (ft_face->glyph->metrics.horiBearingY -
4234 ft_face->glyph->metrics.height) & -64;
4235 lpgm->gmCellIncX = adv;
4236 lpgm->gmCellIncY = 0;
4237 } else {
4238 INT xc, yc;
4239 FT_Vector vec;
4240 for(xc = 0; xc < 2; xc++) {
4241 for(yc = 0; yc < 2; yc++) {
4242 vec.x = (ft_face->glyph->metrics.horiBearingX +
4243 xc * ft_face->glyph->metrics.width);
4244 vec.y = ft_face->glyph->metrics.horiBearingY -
4245 yc * ft_face->glyph->metrics.height;
4246 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4247 pFT_Vector_Transform(&vec, &transMat);
4248 if(xc == 0 && yc == 0) {
4249 left = right = vec.x;
4250 top = bottom = vec.y;
4251 } else {
4252 if(vec.x < left) left = vec.x;
4253 else if(vec.x > right) right = vec.x;
4254 if(vec.y < bottom) bottom = vec.y;
4255 else if(vec.y > top) top = vec.y;
4259 left = left & -64;
4260 right = (right + 63) & -64;
4261 bottom = bottom & -64;
4262 top = (top + 63) & -64;
4264 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4265 vec.x = ft_face->glyph->metrics.horiAdvance;
4266 vec.y = 0;
4267 pFT_Vector_Transform(&vec, &transMat);
4268 lpgm->gmCellIncX = (vec.x+63) >> 6;
4269 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4271 lpgm->gmBlackBoxX = (right - left) >> 6;
4272 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4273 lpgm->gmptGlyphOrigin.x = left >> 6;
4274 lpgm->gmptGlyphOrigin.y = top >> 6;
4276 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4278 FONT_GM(font,original_index)->gm = *lpgm;
4279 FONT_GM(font,original_index)->adv = adv;
4280 FONT_GM(font,original_index)->lsb = lsb;
4281 FONT_GM(font,original_index)->bbx = bbx;
4282 FONT_GM(font,original_index)->init = TRUE;
4285 if(format == GGO_METRICS)
4287 LeaveCriticalSection( &freetype_cs );
4288 return 1; /* FIXME */
4291 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4292 TRACE("loaded a bitmap\n");
4293 LeaveCriticalSection( &freetype_cs );
4294 return GDI_ERROR;
4297 switch(format) {
4298 case GGO_BITMAP:
4299 width = lpgm->gmBlackBoxX;
4300 height = lpgm->gmBlackBoxY;
4301 pitch = ((width + 31) >> 5) << 2;
4302 needed = pitch * height;
4304 if(!buf || !buflen) break;
4306 switch(ft_face->glyph->format) {
4307 case ft_glyph_format_bitmap:
4309 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4310 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4311 INT h = ft_face->glyph->bitmap.rows;
4312 while(h--) {
4313 memcpy(dst, src, w);
4314 src += ft_face->glyph->bitmap.pitch;
4315 dst += pitch;
4317 break;
4320 case ft_glyph_format_outline:
4321 ft_bitmap.width = width;
4322 ft_bitmap.rows = height;
4323 ft_bitmap.pitch = pitch;
4324 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4325 ft_bitmap.buffer = buf;
4327 if(needsTransform) {
4328 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4331 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4333 /* Note: FreeType will only set 'black' bits for us. */
4334 memset(buf, 0, needed);
4335 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4336 break;
4338 default:
4339 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4340 LeaveCriticalSection( &freetype_cs );
4341 return GDI_ERROR;
4343 break;
4345 case GGO_GRAY2_BITMAP:
4346 case GGO_GRAY4_BITMAP:
4347 case GGO_GRAY8_BITMAP:
4348 case WINE_GGO_GRAY16_BITMAP:
4350 unsigned int mult, row, col;
4351 BYTE *start, *ptr;
4353 width = lpgm->gmBlackBoxX;
4354 height = lpgm->gmBlackBoxY;
4355 pitch = (width + 3) / 4 * 4;
4356 needed = pitch * height;
4358 if(!buf || !buflen) break;
4360 switch(ft_face->glyph->format) {
4361 case ft_glyph_format_bitmap:
4363 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4364 INT h = ft_face->glyph->bitmap.rows;
4365 INT x;
4366 while(h--) {
4367 for(x = 0; x < pitch; x++)
4368 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4369 src += ft_face->glyph->bitmap.pitch;
4370 dst += pitch;
4372 LeaveCriticalSection( &freetype_cs );
4373 return needed;
4375 case ft_glyph_format_outline:
4377 ft_bitmap.width = width;
4378 ft_bitmap.rows = height;
4379 ft_bitmap.pitch = pitch;
4380 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4381 ft_bitmap.buffer = buf;
4383 if(needsTransform)
4384 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4386 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4388 memset(ft_bitmap.buffer, 0, buflen);
4390 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4392 if(format == GGO_GRAY2_BITMAP)
4393 mult = 4;
4394 else if(format == GGO_GRAY4_BITMAP)
4395 mult = 16;
4396 else if(format == GGO_GRAY8_BITMAP)
4397 mult = 64;
4398 else /* format == WINE_GGO_GRAY16_BITMAP */
4400 LeaveCriticalSection( &freetype_cs );
4401 return needed;
4403 break;
4405 default:
4406 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4407 LeaveCriticalSection( &freetype_cs );
4408 return GDI_ERROR;
4411 start = buf;
4412 for(row = 0; row < height; row++) {
4413 ptr = start;
4414 for(col = 0; col < width; col++, ptr++) {
4415 *ptr = (((int)*ptr) * mult + 128) / 256;
4417 start += pitch;
4419 break;
4422 case GGO_NATIVE:
4424 int contour, point = 0, first_pt;
4425 FT_Outline *outline = &ft_face->glyph->outline;
4426 TTPOLYGONHEADER *pph;
4427 TTPOLYCURVE *ppc;
4428 DWORD pph_start, cpfx, type;
4430 if(buflen == 0) buf = NULL;
4432 if (needsTransform && buf) {
4433 pFT_Outline_Transform(outline, &transMat);
4436 for(contour = 0; contour < outline->n_contours; contour++) {
4437 pph_start = needed;
4438 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4439 first_pt = point;
4440 if(buf) {
4441 pph->dwType = TT_POLYGON_TYPE;
4442 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4444 needed += sizeof(*pph);
4445 point++;
4446 while(point <= outline->contours[contour]) {
4447 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4448 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4449 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4450 cpfx = 0;
4451 do {
4452 if(buf)
4453 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4454 cpfx++;
4455 point++;
4456 } while(point <= outline->contours[contour] &&
4457 (outline->tags[point] & FT_Curve_Tag_On) ==
4458 (outline->tags[point-1] & FT_Curve_Tag_On));
4459 /* At the end of a contour Windows adds the start point, but
4460 only for Beziers */
4461 if(point > outline->contours[contour] &&
4462 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4463 if(buf)
4464 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4465 cpfx++;
4466 } else if(point <= outline->contours[contour] &&
4467 outline->tags[point] & FT_Curve_Tag_On) {
4468 /* add closing pt for bezier */
4469 if(buf)
4470 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4471 cpfx++;
4472 point++;
4474 if(buf) {
4475 ppc->wType = type;
4476 ppc->cpfx = cpfx;
4478 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4480 if(buf)
4481 pph->cb = needed - pph_start;
4483 break;
4485 case GGO_BEZIER:
4487 /* Convert the quadratic Beziers to cubic Beziers.
4488 The parametric eqn for a cubic Bezier is, from PLRM:
4489 r(t) = at^3 + bt^2 + ct + r0
4490 with the control points:
4491 r1 = r0 + c/3
4492 r2 = r1 + (c + b)/3
4493 r3 = r0 + c + b + a
4495 A quadratic Beizer has the form:
4496 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4498 So equating powers of t leads to:
4499 r1 = 2/3 p1 + 1/3 p0
4500 r2 = 2/3 p1 + 1/3 p2
4501 and of course r0 = p0, r3 = p2
4504 int contour, point = 0, first_pt;
4505 FT_Outline *outline = &ft_face->glyph->outline;
4506 TTPOLYGONHEADER *pph;
4507 TTPOLYCURVE *ppc;
4508 DWORD pph_start, cpfx, type;
4509 FT_Vector cubic_control[4];
4510 if(buflen == 0) buf = NULL;
4512 if (needsTransform && buf) {
4513 pFT_Outline_Transform(outline, &transMat);
4516 for(contour = 0; contour < outline->n_contours; contour++) {
4517 pph_start = needed;
4518 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4519 first_pt = point;
4520 if(buf) {
4521 pph->dwType = TT_POLYGON_TYPE;
4522 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4524 needed += sizeof(*pph);
4525 point++;
4526 while(point <= outline->contours[contour]) {
4527 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4528 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4529 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4530 cpfx = 0;
4531 do {
4532 if(type == TT_PRIM_LINE) {
4533 if(buf)
4534 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4535 cpfx++;
4536 point++;
4537 } else {
4538 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4539 so cpfx = 3n */
4541 /* FIXME: Possible optimization in endpoint calculation
4542 if there are two consecutive curves */
4543 cubic_control[0] = outline->points[point-1];
4544 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4545 cubic_control[0].x += outline->points[point].x + 1;
4546 cubic_control[0].y += outline->points[point].y + 1;
4547 cubic_control[0].x >>= 1;
4548 cubic_control[0].y >>= 1;
4550 if(point+1 > outline->contours[contour])
4551 cubic_control[3] = outline->points[first_pt];
4552 else {
4553 cubic_control[3] = outline->points[point+1];
4554 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4555 cubic_control[3].x += outline->points[point].x + 1;
4556 cubic_control[3].y += outline->points[point].y + 1;
4557 cubic_control[3].x >>= 1;
4558 cubic_control[3].y >>= 1;
4561 /* r1 = 1/3 p0 + 2/3 p1
4562 r2 = 1/3 p2 + 2/3 p1 */
4563 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4564 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4565 cubic_control[2] = cubic_control[1];
4566 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4567 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4568 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4569 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4570 if(buf) {
4571 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4572 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4573 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4575 cpfx += 3;
4576 point++;
4578 } while(point <= outline->contours[contour] &&
4579 (outline->tags[point] & FT_Curve_Tag_On) ==
4580 (outline->tags[point-1] & FT_Curve_Tag_On));
4581 /* At the end of a contour Windows adds the start point,
4582 but only for Beziers and we've already done that.
4584 if(point <= outline->contours[contour] &&
4585 outline->tags[point] & FT_Curve_Tag_On) {
4586 /* This is the closing pt of a bezier, but we've already
4587 added it, so just inc point and carry on */
4588 point++;
4590 if(buf) {
4591 ppc->wType = type;
4592 ppc->cpfx = cpfx;
4594 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4596 if(buf)
4597 pph->cb = needed - pph_start;
4599 break;
4602 default:
4603 FIXME("Unsupported format %d\n", format);
4604 LeaveCriticalSection( &freetype_cs );
4605 return GDI_ERROR;
4607 LeaveCriticalSection( &freetype_cs );
4608 return needed;
4611 static BOOL get_bitmap_text_metrics(GdiFont *font)
4613 FT_Face ft_face = font->ft_face;
4614 #ifdef HAVE_FREETYPE_FTWINFNT_H
4615 FT_WinFNT_HeaderRec winfnt_header;
4616 #endif
4617 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4618 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4619 font->potm->otmSize = size;
4621 #define TM font->potm->otmTextMetrics
4622 #ifdef HAVE_FREETYPE_FTWINFNT_H
4623 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4625 TM.tmHeight = winfnt_header.pixel_height;
4626 TM.tmAscent = winfnt_header.ascent;
4627 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4628 TM.tmInternalLeading = winfnt_header.internal_leading;
4629 TM.tmExternalLeading = winfnt_header.external_leading;
4630 TM.tmAveCharWidth = winfnt_header.avg_width;
4631 TM.tmMaxCharWidth = winfnt_header.max_width;
4632 TM.tmWeight = winfnt_header.weight;
4633 TM.tmOverhang = 0;
4634 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4635 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4636 TM.tmFirstChar = winfnt_header.first_char;
4637 TM.tmLastChar = winfnt_header.last_char;
4638 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4639 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4640 TM.tmItalic = winfnt_header.italic;
4641 TM.tmUnderlined = font->underline;
4642 TM.tmStruckOut = font->strikeout;
4643 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4644 TM.tmCharSet = winfnt_header.charset;
4646 else
4647 #endif
4649 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4650 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4651 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4652 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4653 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4654 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4655 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4656 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4657 TM.tmOverhang = 0;
4658 TM.tmDigitizedAspectX = 96; /* FIXME */
4659 TM.tmDigitizedAspectY = 96; /* FIXME */
4660 TM.tmFirstChar = 1;
4661 TM.tmLastChar = 255;
4662 TM.tmDefaultChar = 32;
4663 TM.tmBreakChar = 32;
4664 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4665 TM.tmUnderlined = font->underline;
4666 TM.tmStruckOut = font->strikeout;
4667 /* NB inverted meaning of TMPF_FIXED_PITCH */
4668 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4669 TM.tmCharSet = font->charset;
4671 #undef TM
4673 return TRUE;
4677 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4679 float scale_x;
4681 if (font->aveWidth)
4683 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4684 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4686 else
4687 scale_x = font->scale_y;
4689 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4690 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4691 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4692 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4693 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4695 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4696 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4699 /*************************************************************
4700 * WineEngGetTextMetrics
4703 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4705 EnterCriticalSection( &freetype_cs );
4706 if(!font->potm) {
4707 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4708 if(!get_bitmap_text_metrics(font))
4710 LeaveCriticalSection( &freetype_cs );
4711 return FALSE;
4714 if(!font->potm)
4716 LeaveCriticalSection( &freetype_cs );
4717 return FALSE;
4719 *ptm = font->potm->otmTextMetrics;
4720 scale_font_metrics(font, ptm);
4721 LeaveCriticalSection( &freetype_cs );
4722 return TRUE;
4726 /*************************************************************
4727 * WineEngGetOutlineTextMetrics
4730 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4731 OUTLINETEXTMETRICW *potm)
4733 FT_Face ft_face = font->ft_face;
4734 UINT needed, lenfam, lensty, ret;
4735 TT_OS2 *pOS2;
4736 TT_HoriHeader *pHori;
4737 TT_Postscript *pPost;
4738 FT_Fixed x_scale, y_scale;
4739 WCHAR *family_nameW, *style_nameW;
4740 static const WCHAR spaceW[] = {' ', '\0'};
4741 char *cp;
4742 INT ascent, descent;
4744 TRACE("font=%p\n", font);
4746 if(!FT_IS_SCALABLE(ft_face))
4747 return 0;
4749 EnterCriticalSection( &freetype_cs );
4751 if(font->potm) {
4752 if(cbSize >= font->potm->otmSize)
4754 memcpy(potm, font->potm, font->potm->otmSize);
4755 scale_font_metrics(font, &potm->otmTextMetrics);
4757 LeaveCriticalSection( &freetype_cs );
4758 return font->potm->otmSize;
4762 needed = sizeof(*potm);
4764 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4765 family_nameW = strdupW(font->name);
4767 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4768 * sizeof(WCHAR);
4769 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4770 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4771 style_nameW, lensty/sizeof(WCHAR));
4773 /* These names should be read from the TT name table */
4775 /* length of otmpFamilyName */
4776 needed += lenfam;
4778 /* length of otmpFaceName */
4779 if(!strcasecmp(ft_face->style_name, "regular")) {
4780 needed += lenfam; /* just the family name */
4781 } else {
4782 needed += lenfam + lensty; /* family + " " + style */
4785 /* length of otmpStyleName */
4786 needed += lensty;
4788 /* length of otmpFullName */
4789 needed += lenfam + lensty;
4792 x_scale = ft_face->size->metrics.x_scale;
4793 y_scale = ft_face->size->metrics.y_scale;
4795 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4796 if(!pOS2) {
4797 FIXME("Can't find OS/2 table - not TT font?\n");
4798 ret = 0;
4799 goto end;
4802 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4803 if(!pHori) {
4804 FIXME("Can't find HHEA table - not TT font?\n");
4805 ret = 0;
4806 goto end;
4809 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4811 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",
4812 pOS2->usWinAscent, pOS2->usWinDescent,
4813 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4814 ft_face->ascender, ft_face->descender, ft_face->height,
4815 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4816 ft_face->bbox.yMax, ft_face->bbox.yMin);
4818 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4819 font->potm->otmSize = needed;
4821 #define TM font->potm->otmTextMetrics
4823 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4824 ascent = pHori->Ascender;
4825 descent = -pHori->Descender;
4826 } else {
4827 ascent = pOS2->usWinAscent;
4828 descent = pOS2->usWinDescent;
4831 if(font->yMax) {
4832 TM.tmAscent = font->yMax;
4833 TM.tmDescent = -font->yMin;
4834 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4835 } else {
4836 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4837 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4838 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4839 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4842 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4844 /* MSDN says:
4845 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4847 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4848 ((ascent + descent) -
4849 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4851 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4852 if (TM.tmAveCharWidth == 0) {
4853 TM.tmAveCharWidth = 1;
4855 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4856 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4857 TM.tmOverhang = 0;
4858 TM.tmDigitizedAspectX = 300;
4859 TM.tmDigitizedAspectY = 300;
4860 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4861 * symbol range to 0 - f0ff
4863 if (font->charset == SYMBOL_CHARSET)
4864 TM.tmFirstChar = 0;
4865 else
4866 TM.tmFirstChar = pOS2->usFirstCharIndex;
4867 TM.tmLastChar = pOS2->usLastCharIndex;
4868 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4869 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4870 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4871 TM.tmUnderlined = font->underline;
4872 TM.tmStruckOut = font->strikeout;
4874 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4875 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4876 (pOS2->version == 0xFFFFU ||
4877 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4878 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4879 else
4880 TM.tmPitchAndFamily = 0;
4882 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4883 case PAN_FAMILY_SCRIPT:
4884 TM.tmPitchAndFamily |= FF_SCRIPT;
4885 break;
4886 case PAN_FAMILY_DECORATIVE:
4887 case PAN_FAMILY_PICTORIAL:
4888 TM.tmPitchAndFamily |= FF_DECORATIVE;
4889 break;
4890 case PAN_FAMILY_TEXT_DISPLAY:
4891 if(TM.tmPitchAndFamily == 0) /* fixed */
4892 TM.tmPitchAndFamily = FF_MODERN;
4893 else {
4894 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4895 case PAN_SERIF_NORMAL_SANS:
4896 case PAN_SERIF_OBTUSE_SANS:
4897 case PAN_SERIF_PERP_SANS:
4898 TM.tmPitchAndFamily |= FF_SWISS;
4899 break;
4900 default:
4901 TM.tmPitchAndFamily |= FF_ROMAN;
4904 break;
4905 default:
4906 TM.tmPitchAndFamily |= FF_DONTCARE;
4909 if(FT_IS_SCALABLE(ft_face))
4910 TM.tmPitchAndFamily |= TMPF_VECTOR;
4912 if(FT_IS_SFNT(ft_face))
4914 if (font->ntmFlags & NTM_PS_OPENTYPE)
4915 TM.tmPitchAndFamily |= TMPF_DEVICE;
4916 else
4917 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4920 TM.tmCharSet = font->charset;
4921 #undef TM
4923 font->potm->otmFiller = 0;
4924 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4925 font->potm->otmfsSelection = pOS2->fsSelection;
4926 font->potm->otmfsType = pOS2->fsType;
4927 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4928 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4929 font->potm->otmItalicAngle = 0; /* POST table */
4930 font->potm->otmEMSquare = ft_face->units_per_EM;
4931 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4932 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4933 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4934 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4935 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4936 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4937 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4938 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4939 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4940 font->potm->otmMacAscent = 0; /* where do these come from ? */
4941 font->potm->otmMacDescent = 0;
4942 font->potm->otmMacLineGap = 0;
4943 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4944 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4945 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4946 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4947 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4948 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4949 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4950 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4951 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4952 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4953 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4954 if(!pPost) {
4955 font->potm->otmsUnderscoreSize = 0;
4956 font->potm->otmsUnderscorePosition = 0;
4957 } else {
4958 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4959 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4962 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4963 cp = (char*)font->potm + sizeof(*font->potm);
4964 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4965 strcpyW((WCHAR*)cp, family_nameW);
4966 cp += lenfam;
4967 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4968 strcpyW((WCHAR*)cp, style_nameW);
4969 cp += lensty;
4970 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4971 strcpyW((WCHAR*)cp, family_nameW);
4972 if(strcasecmp(ft_face->style_name, "regular")) {
4973 strcatW((WCHAR*)cp, spaceW);
4974 strcatW((WCHAR*)cp, style_nameW);
4975 cp += lenfam + lensty;
4976 } else
4977 cp += lenfam;
4978 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4979 strcpyW((WCHAR*)cp, family_nameW);
4980 strcatW((WCHAR*)cp, spaceW);
4981 strcatW((WCHAR*)cp, style_nameW);
4982 ret = needed;
4984 if(potm && needed <= cbSize)
4986 memcpy(potm, font->potm, font->potm->otmSize);
4987 scale_font_metrics(font, &potm->otmTextMetrics);
4990 end:
4991 HeapFree(GetProcessHeap(), 0, style_nameW);
4992 HeapFree(GetProcessHeap(), 0, family_nameW);
4994 LeaveCriticalSection( &freetype_cs );
4995 return ret;
4998 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5000 HFONTLIST *hfontlist;
5001 child->font = alloc_font();
5002 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5003 if(!child->font->ft_face)
5005 free_font(child->font);
5006 child->font = NULL;
5007 return FALSE;
5010 child->font->ntmFlags = child->face->ntmFlags;
5011 child->font->orientation = font->orientation;
5012 child->font->scale_y = font->scale_y;
5013 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5014 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5015 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5016 child->font->base_font = font;
5017 list_add_head(&child_font_list, &child->font->entry);
5018 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5019 return TRUE;
5022 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5024 FT_UInt g;
5025 CHILD_FONT *child_font;
5027 if(font->base_font)
5028 font = font->base_font;
5030 *linked_font = font;
5032 if((*glyph = get_glyph_index(font, c)))
5033 return TRUE;
5035 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5037 if(!child_font->font)
5038 if(!load_child_font(font, child_font))
5039 continue;
5041 if(!child_font->font->ft_face)
5042 continue;
5043 g = get_glyph_index(child_font->font, c);
5044 if(g)
5046 *glyph = g;
5047 *linked_font = child_font->font;
5048 return TRUE;
5051 return FALSE;
5054 /*************************************************************
5055 * WineEngGetCharWidth
5058 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5059 LPINT buffer)
5061 UINT c;
5062 GLYPHMETRICS gm;
5063 FT_UInt glyph_index;
5064 GdiFont *linked_font;
5066 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5068 EnterCriticalSection( &freetype_cs );
5069 for(c = firstChar; c <= lastChar; c++) {
5070 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5071 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5072 &gm, 0, NULL, NULL);
5073 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5075 LeaveCriticalSection( &freetype_cs );
5076 return TRUE;
5079 /*************************************************************
5080 * WineEngGetCharABCWidths
5083 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5084 LPABC buffer)
5086 UINT c;
5087 GLYPHMETRICS gm;
5088 FT_UInt glyph_index;
5089 GdiFont *linked_font;
5091 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5093 if(!FT_IS_SCALABLE(font->ft_face))
5094 return FALSE;
5096 EnterCriticalSection( &freetype_cs );
5098 for(c = firstChar; c <= lastChar; c++) {
5099 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5100 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5101 &gm, 0, NULL, NULL);
5102 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5103 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5104 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5105 FONT_GM(linked_font,glyph_index)->bbx;
5107 LeaveCriticalSection( &freetype_cs );
5108 return TRUE;
5111 /*************************************************************
5112 * WineEngGetCharABCWidthsI
5115 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5116 LPABC buffer)
5118 UINT c;
5119 GLYPHMETRICS gm;
5120 FT_UInt glyph_index;
5121 GdiFont *linked_font;
5123 if(!FT_HAS_HORIZONTAL(font->ft_face))
5124 return FALSE;
5126 EnterCriticalSection( &freetype_cs );
5128 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5129 if (!pgi)
5130 for(c = firstChar; c < firstChar+count; c++) {
5131 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5132 &gm, 0, NULL, NULL);
5133 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5134 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5135 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5136 - FONT_GM(linked_font,c)->bbx;
5138 else
5139 for(c = 0; c < count; c++) {
5140 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5141 &gm, 0, NULL, NULL);
5142 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5143 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5144 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5145 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5148 LeaveCriticalSection( &freetype_cs );
5149 return TRUE;
5152 /*************************************************************
5153 * WineEngGetTextExtentExPoint
5156 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5157 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5159 INT idx;
5160 INT nfit = 0, ext;
5161 GLYPHMETRICS gm;
5162 TEXTMETRICW tm;
5163 FT_UInt glyph_index;
5164 GdiFont *linked_font;
5166 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5167 max_ext, size);
5169 EnterCriticalSection( &freetype_cs );
5171 size->cx = 0;
5172 WineEngGetTextMetrics(font, &tm);
5173 size->cy = tm.tmHeight;
5175 for(idx = 0; idx < count; idx++) {
5176 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5177 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5178 &gm, 0, NULL, NULL);
5179 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5180 ext = size->cx;
5181 if (! pnfit || ext <= max_ext) {
5182 ++nfit;
5183 if (dxs)
5184 dxs[idx] = ext;
5188 if (pnfit)
5189 *pnfit = nfit;
5191 LeaveCriticalSection( &freetype_cs );
5192 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5193 return TRUE;
5196 /*************************************************************
5197 * WineEngGetTextExtentExPointI
5200 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5201 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5203 INT idx;
5204 INT nfit = 0, ext;
5205 GLYPHMETRICS gm;
5206 TEXTMETRICW tm;
5208 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5210 EnterCriticalSection( &freetype_cs );
5212 size->cx = 0;
5213 WineEngGetTextMetrics(font, &tm);
5214 size->cy = tm.tmHeight;
5216 for(idx = 0; idx < count; idx++) {
5217 WineEngGetGlyphOutline(font, indices[idx],
5218 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5219 NULL);
5220 size->cx += FONT_GM(font,indices[idx])->adv;
5221 ext = size->cx;
5222 if (! pnfit || ext <= max_ext) {
5223 ++nfit;
5224 if (dxs)
5225 dxs[idx] = ext;
5229 if (pnfit)
5230 *pnfit = nfit;
5232 LeaveCriticalSection( &freetype_cs );
5233 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5234 return TRUE;
5237 /*************************************************************
5238 * WineEngGetFontData
5241 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5242 DWORD cbData)
5244 FT_Face ft_face = font->ft_face;
5245 FT_ULong len;
5246 FT_Error err;
5248 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5249 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5250 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5252 if(!FT_IS_SFNT(ft_face))
5253 return GDI_ERROR;
5255 if(!buf || !cbData)
5256 len = 0;
5257 else
5258 len = cbData;
5260 if(table) { /* MS tags differ in endidness from FT ones */
5261 table = table >> 24 | table << 24 |
5262 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5265 /* make sure value of len is the value freetype says it needs */
5266 if(buf && len)
5268 FT_ULong needed = 0;
5269 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5270 if( !err && needed < len) len = needed;
5272 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5274 if(err) {
5275 TRACE("Can't find table %c%c%c%c\n",
5276 /* bytes were reversed */
5277 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5278 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5279 return GDI_ERROR;
5281 return len;
5284 /*************************************************************
5285 * WineEngGetTextFace
5288 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5290 if(str) {
5291 lstrcpynW(str, font->name, count);
5292 return strlenW(font->name);
5293 } else
5294 return strlenW(font->name) + 1;
5297 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5299 if (fs) *fs = font->fs;
5300 return font->charset;
5303 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5305 GdiFont *font = dc->gdiFont, *linked_font;
5306 struct list *first_hfont;
5307 BOOL ret;
5309 EnterCriticalSection( &freetype_cs );
5310 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5311 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5312 if(font == linked_font)
5313 *new_hfont = dc->hFont;
5314 else
5316 first_hfont = list_head(&linked_font->hfontlist);
5317 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5319 LeaveCriticalSection( &freetype_cs );
5320 return ret;
5323 /* Retrieve a list of supported Unicode ranges for a given font.
5324 * Can be called with NULL gs to calculate the buffer size. Returns
5325 * the number of ranges found.
5327 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5329 DWORD num_ranges = 0;
5331 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5333 FT_UInt glyph_code;
5334 FT_ULong char_code, char_code_prev;
5336 glyph_code = 0;
5337 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5339 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5340 face->num_glyphs, glyph_code, char_code);
5342 if (!glyph_code) return 0;
5344 if (gs)
5346 gs->ranges[0].wcLow = (USHORT)char_code;
5347 gs->ranges[0].cGlyphs = 0;
5348 gs->cGlyphsSupported = 0;
5351 num_ranges = 1;
5352 while (glyph_code)
5354 if (char_code < char_code_prev)
5356 ERR("expected increasing char code from FT_Get_Next_Char\n");
5357 return 0;
5359 if (char_code - char_code_prev > 1)
5361 num_ranges++;
5362 if (gs)
5364 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5365 gs->ranges[num_ranges - 1].cGlyphs = 1;
5366 gs->cGlyphsSupported++;
5369 else if (gs)
5371 gs->ranges[num_ranges - 1].cGlyphs++;
5372 gs->cGlyphsSupported++;
5374 char_code_prev = char_code;
5375 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5378 else
5379 FIXME("encoding %u not supported\n", face->charmap->encoding);
5381 return num_ranges;
5384 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5386 DWORD size = 0;
5387 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5389 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5390 if (glyphset)
5392 glyphset->cbThis = size;
5393 glyphset->cRanges = num_ranges;
5395 return size;
5398 /*************************************************************
5399 * FontIsLinked
5401 BOOL WineEngFontIsLinked(GdiFont *font)
5403 BOOL ret;
5404 EnterCriticalSection( &freetype_cs );
5405 ret = !list_empty(&font->child_fonts);
5406 LeaveCriticalSection( &freetype_cs );
5407 return ret;
5410 static BOOL is_hinting_enabled(void)
5412 /* Use the >= 2.2.0 function if available */
5413 if(pFT_Get_TrueType_Engine_Type)
5415 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5416 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5418 #ifdef FT_DRIVER_HAS_HINTER
5419 else
5421 FT_Module mod;
5423 /* otherwise if we've been compiled with < 2.2.0 headers
5424 use the internal macro */
5425 mod = pFT_Get_Module(library, "truetype");
5426 if(mod && FT_DRIVER_HAS_HINTER(mod))
5427 return TRUE;
5429 #endif
5431 return FALSE;
5434 /*************************************************************************
5435 * GetRasterizerCaps (GDI32.@)
5437 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5439 static int hinting = -1;
5441 if(hinting == -1)
5443 hinting = is_hinting_enabled();
5444 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5447 lprs->nSize = sizeof(RASTERIZER_STATUS);
5448 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5449 lprs->nLanguageID = 0;
5450 return TRUE;
5453 /*************************************************************************
5454 * Kerning support for TrueType fonts
5456 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5458 struct TT_kern_table
5460 USHORT version;
5461 USHORT nTables;
5464 struct TT_kern_subtable
5466 USHORT version;
5467 USHORT length;
5468 union
5470 USHORT word;
5471 struct
5473 USHORT horizontal : 1;
5474 USHORT minimum : 1;
5475 USHORT cross_stream: 1;
5476 USHORT override : 1;
5477 USHORT reserved1 : 4;
5478 USHORT format : 8;
5479 } bits;
5480 } coverage;
5483 struct TT_format0_kern_subtable
5485 USHORT nPairs;
5486 USHORT searchRange;
5487 USHORT entrySelector;
5488 USHORT rangeShift;
5491 struct TT_kern_pair
5493 USHORT left;
5494 USHORT right;
5495 short value;
5498 static DWORD parse_format0_kern_subtable(GdiFont *font,
5499 const struct TT_format0_kern_subtable *tt_f0_ks,
5500 const USHORT *glyph_to_char,
5501 KERNINGPAIR *kern_pair, DWORD cPairs)
5503 USHORT i, nPairs;
5504 const struct TT_kern_pair *tt_kern_pair;
5506 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5508 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5510 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5511 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5512 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5514 if (!kern_pair || !cPairs)
5515 return nPairs;
5517 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5519 nPairs = min(nPairs, cPairs);
5521 for (i = 0; i < nPairs; i++)
5523 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5524 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5525 /* this algorithm appears to better match what Windows does */
5526 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5527 if (kern_pair->iKernAmount < 0)
5529 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5530 kern_pair->iKernAmount -= font->ppem;
5532 else if (kern_pair->iKernAmount > 0)
5534 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5535 kern_pair->iKernAmount += font->ppem;
5537 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5539 TRACE("left %u right %u value %d\n",
5540 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5542 kern_pair++;
5544 TRACE("copied %u entries\n", nPairs);
5545 return nPairs;
5548 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5550 DWORD length;
5551 void *buf;
5552 const struct TT_kern_table *tt_kern_table;
5553 const struct TT_kern_subtable *tt_kern_subtable;
5554 USHORT i, nTables;
5555 USHORT *glyph_to_char;
5557 EnterCriticalSection( &freetype_cs );
5558 if (font->total_kern_pairs != (DWORD)-1)
5560 if (cPairs && kern_pair)
5562 cPairs = min(cPairs, font->total_kern_pairs);
5563 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5564 LeaveCriticalSection( &freetype_cs );
5565 return cPairs;
5567 LeaveCriticalSection( &freetype_cs );
5568 return font->total_kern_pairs;
5571 font->total_kern_pairs = 0;
5573 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5575 if (length == GDI_ERROR)
5577 TRACE("no kerning data in the font\n");
5578 LeaveCriticalSection( &freetype_cs );
5579 return 0;
5582 buf = HeapAlloc(GetProcessHeap(), 0, length);
5583 if (!buf)
5585 WARN("Out of memory\n");
5586 LeaveCriticalSection( &freetype_cs );
5587 return 0;
5590 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5592 /* build a glyph index to char code map */
5593 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5594 if (!glyph_to_char)
5596 WARN("Out of memory allocating a glyph index to char code map\n");
5597 HeapFree(GetProcessHeap(), 0, buf);
5598 LeaveCriticalSection( &freetype_cs );
5599 return 0;
5602 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5604 FT_UInt glyph_code;
5605 FT_ULong char_code;
5607 glyph_code = 0;
5608 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5610 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5611 font->ft_face->num_glyphs, glyph_code, char_code);
5613 while (glyph_code)
5615 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5617 /* FIXME: This doesn't match what Windows does: it does some fancy
5618 * things with duplicate glyph index to char code mappings, while
5619 * we just avoid overriding existing entries.
5621 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5622 glyph_to_char[glyph_code] = (USHORT)char_code;
5624 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5627 else
5629 ULONG n;
5631 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5632 for (n = 0; n <= 65535; n++)
5633 glyph_to_char[n] = (USHORT)n;
5636 tt_kern_table = buf;
5637 nTables = GET_BE_WORD(tt_kern_table->nTables);
5638 TRACE("version %u, nTables %u\n",
5639 GET_BE_WORD(tt_kern_table->version), nTables);
5641 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5643 for (i = 0; i < nTables; i++)
5645 struct TT_kern_subtable tt_kern_subtable_copy;
5647 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5648 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5649 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5651 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5652 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5653 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5655 /* According to the TrueType specification this is the only format
5656 * that will be properly interpreted by Windows and OS/2
5658 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5660 DWORD new_chunk, old_total = font->total_kern_pairs;
5662 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5663 glyph_to_char, NULL, 0);
5664 font->total_kern_pairs += new_chunk;
5666 if (!font->kern_pairs)
5667 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5668 font->total_kern_pairs * sizeof(*font->kern_pairs));
5669 else
5670 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5671 font->total_kern_pairs * sizeof(*font->kern_pairs));
5673 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5674 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5676 else
5677 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5679 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5682 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5683 HeapFree(GetProcessHeap(), 0, buf);
5685 if (cPairs && kern_pair)
5687 cPairs = min(cPairs, font->total_kern_pairs);
5688 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5689 LeaveCriticalSection( &freetype_cs );
5690 return cPairs;
5692 LeaveCriticalSection( &freetype_cs );
5693 return font->total_kern_pairs;
5696 #else /* HAVE_FREETYPE */
5698 /*************************************************************************/
5700 BOOL WineEngInit(void)
5702 return FALSE;
5704 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5706 return NULL;
5708 BOOL WineEngDestroyFontInstance(HFONT hfont)
5710 return FALSE;
5713 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5715 return 1;
5718 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5719 LPWORD pgi, DWORD flags)
5721 return GDI_ERROR;
5724 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5725 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5726 const MAT2* lpmat)
5728 ERR("called but we don't have FreeType\n");
5729 return GDI_ERROR;
5732 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5734 ERR("called but we don't have FreeType\n");
5735 return FALSE;
5738 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5739 OUTLINETEXTMETRICW *potm)
5741 ERR("called but we don't have FreeType\n");
5742 return 0;
5745 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5746 LPINT buffer)
5748 ERR("called but we don't have FreeType\n");
5749 return FALSE;
5752 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5753 LPABC buffer)
5755 ERR("called but we don't have FreeType\n");
5756 return FALSE;
5759 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5760 LPABC buffer)
5762 ERR("called but we don't have FreeType\n");
5763 return FALSE;
5766 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5767 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5769 ERR("called but we don't have FreeType\n");
5770 return FALSE;
5773 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5774 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5776 ERR("called but we don't have FreeType\n");
5777 return FALSE;
5780 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5781 DWORD cbData)
5783 ERR("called but we don't have FreeType\n");
5784 return GDI_ERROR;
5787 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5789 ERR("called but we don't have FreeType\n");
5790 return 0;
5793 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5795 FIXME(":stub\n");
5796 return 1;
5799 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5801 FIXME(":stub\n");
5802 return TRUE;
5805 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5807 FIXME(":stub\n");
5808 return NULL;
5811 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5813 FIXME(":stub\n");
5814 return DEFAULT_CHARSET;
5817 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5819 return FALSE;
5822 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5824 FIXME("(%p, %p): stub\n", font, glyphset);
5825 return 0;
5828 BOOL WineEngFontIsLinked(GdiFont *font)
5830 return FALSE;
5833 /*************************************************************************
5834 * GetRasterizerCaps (GDI32.@)
5836 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5838 lprs->nSize = sizeof(RASTERIZER_STATUS);
5839 lprs->wFlags = 0;
5840 lprs->nLanguageID = 0;
5841 return TRUE;
5844 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5846 ERR("called but we don't have FreeType\n");
5847 return 0;
5850 #endif /* HAVE_FREETYPE */