gdi32: Fix lfWidth before caching the font to avoid duplicate entries in the cache.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobb00bc71a4492cb96a3c655b12557041ecbc013fe
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 basically 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 FONTSIGNATURE fs;
260 FONTSIGNATURE fs_links;
261 DWORD ntmFlags;
262 FT_Fixed font_version;
263 BOOL scalable;
264 Bitmap_Size size; /* set if face is a bitmap */
265 BOOL external; /* TRUE if we should manually add this font to the registry */
266 struct tagFamily *family;
267 /* Cached data for Enum */
268 struct enum_data *cached_enum_data;
269 } Face;
271 typedef struct tagFamily {
272 struct list entry;
273 const WCHAR *FamilyName;
274 struct list faces;
275 } Family;
277 typedef struct {
278 GLYPHMETRICS gm;
279 INT adv; /* These three hold to widths of the unrotated chars */
280 INT lsb;
281 INT bbx;
282 BOOL init;
283 } GM;
285 typedef struct {
286 FLOAT eM11, eM12;
287 FLOAT eM21, eM22;
288 } FMAT2;
290 typedef struct {
291 DWORD hash;
292 LOGFONTW lf;
293 FMAT2 matrix;
294 BOOL can_use_bitmap;
295 } FONT_DESC;
297 typedef struct tagHFONTLIST {
298 struct list entry;
299 HFONT hfont;
300 } HFONTLIST;
302 typedef struct {
303 struct list entry;
304 Face *face;
305 GdiFont *font;
306 } CHILD_FONT;
308 struct tagGdiFont {
309 struct list entry;
310 GM **gm;
311 DWORD gmsize;
312 struct list hfontlist;
313 OUTLINETEXTMETRICW *potm;
314 DWORD total_kern_pairs;
315 KERNINGPAIR *kern_pairs;
316 struct list child_fonts;
318 /* the following members can be accessed without locking, they are never modified after creation */
319 FT_Face ft_face;
320 struct font_mapping *mapping;
321 LPWSTR name;
322 int charset;
323 int codepage;
324 BOOL fake_italic;
325 BOOL fake_bold;
326 BYTE underline;
327 BYTE strikeout;
328 INT orientation;
329 FONT_DESC font_desc;
330 LONG aveWidth, ppem;
331 float scale_y;
332 SHORT yMax;
333 SHORT yMin;
334 DWORD ntmFlags;
335 FONTSIGNATURE fs;
336 GdiFont *base_font;
337 VOID *GSUB_Table;
340 typedef struct {
341 struct list entry;
342 const WCHAR *font_name;
343 struct list links;
344 } SYSTEM_LINKS;
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
350 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list = LIST_INIT(child_font_list);
353 static struct list system_links = LIST_INIT(system_links);
355 static struct list font_subst_list = LIST_INIT(font_subst_list);
357 static struct list font_list = LIST_INIT(font_list);
359 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
365 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
366 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372 'W','i','n','d','o','w','s',' ','N','T','\\',
373 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374 'F','o','n','t','s','\0'};
376 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
377 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
378 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
379 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
381 static const WCHAR * const SystemFontValues[4] = {
382 System_Value,
383 OEMFont_Value,
384 FixedSys_Value,
385 NULL
388 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
389 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
391 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
392 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
393 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
394 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
395 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
396 'E','u','r','o','p','e','a','n','\0'};
397 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
398 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
399 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
400 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
401 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
402 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
403 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
404 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
405 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
406 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
407 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
408 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
410 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
411 WesternW, /*00*/
412 Central_EuropeanW,
413 CyrillicW,
414 GreekW,
415 TurkishW,
416 HebrewW,
417 ArabicW,
418 BalticW,
419 VietnameseW, /*08*/
420 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
421 ThaiW,
422 JapaneseW,
423 CHINESE_GB2312W,
424 HangulW,
425 CHINESE_BIG5W,
426 Hangul_Johab_W,
427 NULL, NULL, /*23*/
428 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
429 SymbolW /*31*/
432 typedef struct {
433 WCHAR *name;
434 INT charset;
435 } NameCs;
437 typedef struct tagFontSubst {
438 struct list entry;
439 NameCs from;
440 NameCs to;
441 } FontSubst;
443 struct font_mapping
445 struct list entry;
446 int refcount;
447 dev_t dev;
448 ino_t ino;
449 void *data;
450 size_t size;
453 static struct list mappings_list = LIST_INIT( mappings_list );
455 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
457 static CRITICAL_SECTION freetype_cs;
458 static CRITICAL_SECTION_DEBUG critsect_debug =
460 0, 0, &freetype_cs,
461 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
462 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
464 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
466 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
468 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
469 static BOOL use_default_fallback = FALSE;
471 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
473 /****************************************
474 * Notes on .fon files
476 * The fonts System, FixedSys and Terminal are special. There are typically multiple
477 * versions installed for different resolutions and codepages. Windows stores which one to use
478 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
479 * Key Meaning
480 * FIXEDFON.FON FixedSys
481 * FONTS.FON System
482 * OEMFONT.FON Terminal
483 * LogPixels Current dpi set by the display control panel applet
484 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
485 * also has a LogPixels value that appears to mirror this)
487 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
488 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
489 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
490 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
491 * so that makes sense.
493 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
494 * to be mapped into the registry on Windows 2000 at least).
495 * I have
496 * woafont=app850.fon
497 * ega80woa.fon=ega80850.fon
498 * ega40woa.fon=ega40850.fon
499 * cga80woa.fon=cga80850.fon
500 * cga40woa.fon=cga40850.fon
503 /* These are all structures needed for the GSUB table */
505 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
506 #define TATEGAKI_LOWER_BOUND 0x02F1
508 typedef struct {
509 DWORD version;
510 WORD ScriptList;
511 WORD FeatureList;
512 WORD LookupList;
513 } GSUB_Header;
515 typedef struct {
516 CHAR ScriptTag[4];
517 WORD Script;
518 } GSUB_ScriptRecord;
520 typedef struct {
521 WORD ScriptCount;
522 GSUB_ScriptRecord ScriptRecord[1];
523 } GSUB_ScriptList;
525 typedef struct {
526 CHAR LangSysTag[4];
527 WORD LangSys;
528 } GSUB_LangSysRecord;
530 typedef struct {
531 WORD DefaultLangSys;
532 WORD LangSysCount;
533 GSUB_LangSysRecord LangSysRecord[1];
534 } GSUB_Script;
536 typedef struct {
537 WORD LookupOrder; /* Reserved */
538 WORD ReqFeatureIndex;
539 WORD FeatureCount;
540 WORD FeatureIndex[1];
541 } GSUB_LangSys;
543 typedef struct {
544 CHAR FeatureTag[4];
545 WORD Feature;
546 } GSUB_FeatureRecord;
548 typedef struct {
549 WORD FeatureCount;
550 GSUB_FeatureRecord FeatureRecord[1];
551 } GSUB_FeatureList;
553 typedef struct {
554 WORD FeatureParams; /* Reserved */
555 WORD LookupCount;
556 WORD LookupListIndex[1];
557 } GSUB_Feature;
559 typedef struct {
560 WORD LookupCount;
561 WORD Lookup[1];
562 } GSUB_LookupList;
564 typedef struct {
565 WORD LookupType;
566 WORD LookupFlag;
567 WORD SubTableCount;
568 WORD SubTable[1];
569 } GSUB_LookupTable;
571 typedef struct {
572 WORD CoverageFormat;
573 WORD GlyphCount;
574 WORD GlyphArray[1];
575 } GSUB_CoverageFormat1;
577 typedef struct {
578 WORD Start;
579 WORD End;
580 WORD StartCoverageIndex;
581 } GSUB_RangeRecord;
583 typedef struct {
584 WORD CoverageFormat;
585 WORD RangeCount;
586 GSUB_RangeRecord RangeRecord[1];
587 } GSUB_CoverageFormat2;
589 typedef struct {
590 WORD SubstFormat; /* = 1 */
591 WORD Coverage;
592 WORD DeltaGlyphID;
593 } GSUB_SingleSubstFormat1;
595 typedef struct {
596 WORD SubstFormat; /* = 2 */
597 WORD Coverage;
598 WORD GlyphCount;
599 WORD Substitute[1];
600 }GSUB_SingleSubstFormat2;
602 #ifdef HAVE_CARBON_CARBON_H
603 static char *find_cache_dir(void)
605 FSRef ref;
606 OSErr err;
607 static char cached_path[MAX_PATH];
608 static const char *wine = "/Wine", *fonts = "/Fonts";
610 if(*cached_path) return cached_path;
612 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
613 if(err != noErr)
615 WARN("can't create cached data folder\n");
616 return NULL;
618 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
619 if(err != noErr)
621 WARN("can't create cached data path\n");
622 *cached_path = '\0';
623 return NULL;
625 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
627 ERR("Could not create full path\n");
628 *cached_path = '\0';
629 return NULL;
631 strcat(cached_path, wine);
633 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
635 WARN("Couldn't mkdir %s\n", cached_path);
636 *cached_path = '\0';
637 return NULL;
639 strcat(cached_path, fonts);
640 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
642 WARN("Couldn't mkdir %s\n", cached_path);
643 *cached_path = '\0';
644 return NULL;
646 return cached_path;
649 /******************************************************************
650 * expand_mac_font
652 * Extracts individual TrueType font files from a Mac suitcase font
653 * and saves them into the user's caches directory (see
654 * find_cache_dir()).
655 * Returns a NULL terminated array of filenames.
657 * We do this because they are apps that try to read ttf files
658 * themselves and they don't like Mac suitcase files.
660 static char **expand_mac_font(const char *path)
662 FSRef ref;
663 SInt16 res_ref;
664 OSStatus s;
665 unsigned int idx;
666 const char *out_dir;
667 const char *filename;
668 int output_len;
669 struct {
670 char **array;
671 unsigned int size, max_size;
672 } ret;
674 TRACE("path %s\n", path);
676 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
677 if(s != noErr)
679 WARN("failed to get ref\n");
680 return NULL;
683 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
684 if(s != noErr)
686 TRACE("no data fork, so trying resource fork\n");
687 res_ref = FSOpenResFile(&ref, fsRdPerm);
688 if(res_ref == -1)
690 TRACE("unable to open resource fork\n");
691 return NULL;
695 ret.size = 0;
696 ret.max_size = 10;
697 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
698 if(!ret.array)
700 CloseResFile(res_ref);
701 return NULL;
704 out_dir = find_cache_dir();
706 filename = strrchr(path, '/');
707 if(!filename) filename = path;
708 else filename++;
710 /* output filename has the form out_dir/filename_%04x.ttf */
711 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
713 UseResFile(res_ref);
714 idx = 1;
715 while(1)
717 FamRec *fam_rec;
718 unsigned short *num_faces_ptr, num_faces, face;
719 AsscEntry *assoc;
720 Handle fond;
721 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
723 fond = Get1IndResource(fond_res, idx);
724 if(!fond) break;
725 TRACE("got fond resource %d\n", idx);
726 HLock(fond);
728 fam_rec = *(FamRec**)fond;
729 num_faces_ptr = (unsigned short *)(fam_rec + 1);
730 num_faces = GET_BE_WORD(*num_faces_ptr);
731 num_faces++;
732 assoc = (AsscEntry*)(num_faces_ptr + 1);
733 TRACE("num faces %04x\n", num_faces);
734 for(face = 0; face < num_faces; face++, assoc++)
736 Handle sfnt;
737 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
738 unsigned short size, font_id;
739 char *output;
741 size = GET_BE_WORD(assoc->fontSize);
742 font_id = GET_BE_WORD(assoc->fontID);
743 if(size != 0)
745 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
746 continue;
749 TRACE("trying to load sfnt id %04x\n", font_id);
750 sfnt = GetResource(sfnt_res, font_id);
751 if(!sfnt)
753 TRACE("can't get sfnt resource %04x\n", font_id);
754 continue;
757 output = HeapAlloc(GetProcessHeap(), 0, output_len);
758 if(output)
760 int fd;
762 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
764 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
765 if(fd != -1 || errno == EEXIST)
767 if(fd != -1)
769 unsigned char *sfnt_data;
771 HLock(sfnt);
772 sfnt_data = *(unsigned char**)sfnt;
773 write(fd, sfnt_data, GetHandleSize(sfnt));
774 HUnlock(sfnt);
775 close(fd);
777 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
779 ret.max_size *= 2;
780 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
782 ret.array[ret.size++] = output;
784 else
786 WARN("unable to create %s\n", output);
787 HeapFree(GetProcessHeap(), 0, output);
790 ReleaseResource(sfnt);
792 HUnlock(fond);
793 ReleaseResource(fond);
794 idx++;
796 CloseResFile(res_ref);
798 return ret.array;
801 #endif /* HAVE_CARBON_CARBON_H */
803 static inline BOOL is_win9x(void)
805 return GetVersion() & 0x80000000;
808 This function builds an FT_Fixed from a float. It puts the integer part
809 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
810 It fails if the integer part of the float number is greater than SHORT_MAX.
812 static inline FT_Fixed FT_FixedFromFloat(float f)
814 short value = f;
815 unsigned short fract = (f - value) * 0xFFFF;
816 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
825 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
829 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
831 Family *family;
832 Face *face;
833 const char *file;
834 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
835 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
837 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
840 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
842 if(face_name && strcmpiW(face_name, family->FamilyName))
843 continue;
844 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
846 if (!face->file)
847 continue;
848 file = strrchr(face->file, '/');
849 if(!file)
850 file = face->file;
851 else
852 file++;
853 if(!strcasecmp(file, file_nameA))
855 HeapFree(GetProcessHeap(), 0, file_nameA);
856 return face;
860 HeapFree(GetProcessHeap(), 0, file_nameA);
861 return NULL;
864 static Family *find_family_from_name(const WCHAR *name)
866 Family *family;
868 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
870 if(!strcmpiW(family->FamilyName, name))
871 return family;
874 return NULL;
877 static void DumpSubstList(void)
879 FontSubst *psub;
881 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
883 if(psub->from.charset != -1 || psub->to.charset != -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
885 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
886 else
887 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
888 debugstr_w(psub->to.name));
890 return;
893 static LPWSTR strdupW(LPCWSTR p)
895 LPWSTR ret;
896 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
897 ret = HeapAlloc(GetProcessHeap(), 0, len);
898 memcpy(ret, p, len);
899 return ret;
902 static LPSTR strdupA(LPCSTR p)
904 LPSTR ret;
905 DWORD len = (strlen(p) + 1);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
907 memcpy(ret, p, len);
908 return ret;
911 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
912 INT from_charset)
914 FontSubst *element;
916 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
918 if(!strcmpiW(element->from.name, from_name) &&
919 (element->from.charset == from_charset ||
920 element->from.charset == -1))
921 return element;
924 return NULL;
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
931 FontSubst *from_exist, *to_exist;
933 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
935 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
937 list_remove(&from_exist->entry);
938 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
939 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
940 HeapFree(GetProcessHeap(), 0, from_exist);
941 from_exist = NULL;
944 if(!from_exist)
946 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
948 if(to_exist)
950 HeapFree(GetProcessHeap(), 0, subst->to.name);
951 subst->to.name = strdupW(to_exist->to.name);
954 list_add_tail(subst_list, &subst->entry);
956 return TRUE;
959 HeapFree(GetProcessHeap(), 0, subst->from.name);
960 HeapFree(GetProcessHeap(), 0, subst->to.name);
961 HeapFree(GetProcessHeap(), 0, subst);
962 return FALSE;
965 static void split_subst_info(NameCs *nc, LPSTR str)
967 CHAR *p = strrchr(str, ',');
968 DWORD len;
970 nc->charset = -1;
971 if(p && *(p+1)) {
972 nc->charset = strtol(p+1, NULL, 10);
973 *p = '\0';
975 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
976 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
980 static void LoadSubstList(void)
982 FontSubst *psub;
983 HKEY hkey;
984 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
985 LPSTR value;
986 LPVOID data;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey) == ERROR_SUCCESS) {
992 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 &valuelen, &datalen, NULL, NULL);
995 valuelen++; /* returned value doesn't include room for '\0' */
996 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
997 data = HeapAlloc(GetProcessHeap(), 0, datalen);
999 dlen = datalen;
1000 vlen = valuelen;
1001 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1002 &dlen) == ERROR_SUCCESS) {
1003 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1005 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1006 split_subst_info(&psub->from, value);
1007 split_subst_info(&psub->to, data);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if((psub->to.charset != psub->from.charset) ||
1012 psub->to.charset == DEFAULT_CHARSET) {
1013 HeapFree(GetProcessHeap(), 0, psub->to.name);
1014 HeapFree(GetProcessHeap(), 0, psub->from.name);
1015 HeapFree(GetProcessHeap(), 0, psub);
1016 } else {
1017 add_font_subst(&font_subst_list, psub, 0);
1019 /* reset dlen and vlen */
1020 dlen = datalen;
1021 vlen = valuelen;
1023 HeapFree(GetProcessHeap(), 0, data);
1024 HeapFree(GetProcessHeap(), 0, value);
1025 RegCloseKey(hkey);
1029 static WCHAR *get_familyname(FT_Face ft_face)
1031 WCHAR *family = NULL;
1032 FT_SfntName name;
1033 FT_UInt num_names, name_index, i;
1035 if(FT_IS_SFNT(ft_face))
1037 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1039 for(name_index = 0; name_index < num_names; name_index++)
1041 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1043 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1044 (name.language_id == GetUserDefaultLCID()) &&
1045 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1046 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1048 /* String is not nul terminated and string_len is a byte length. */
1049 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1050 for(i = 0; i < name.string_len / 2; i++)
1052 WORD *tmp = (WORD *)&name.string[i * 2];
1053 family[i] = GET_BE_WORD(*tmp);
1055 family[i] = 0;
1057 TRACE("Got localised name %s\n", debugstr_w(family));
1058 return family;
1064 return NULL;
1068 /*****************************************************************
1069 * load_sfnt_table
1071 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1072 * of FreeType that don't export this function.
1075 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1078 FT_Error err;
1080 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1081 if(pFT_Load_Sfnt_Table)
1083 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1085 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1086 else /* Do it the hard way */
1088 TT_Face tt_face = (TT_Face) ft_face;
1089 SFNT_Interface *sfnt;
1090 if (FT_Version.major==2 && FT_Version.minor==0)
1092 /* 2.0.x */
1093 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1095 else
1097 /* A field was added in the middle of the structure in 2.1.x */
1098 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1100 err = sfnt->load_any(tt_face, table, offset, buf, len);
1102 #else
1103 else
1105 static int msg;
1106 if(!msg)
1108 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1109 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1110 "Please upgrade your freetype library.\n");
1111 msg++;
1113 err = FT_Err_Unimplemented_Feature;
1115 #endif
1116 return err;
1120 #define ADDFONT_EXTERNAL_FONT 0x01
1121 #define ADDFONT_FORCE_BITMAP 0x02
1122 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1124 FT_Face ft_face;
1125 TT_OS2 *pOS2;
1126 TT_Header *pHeader = NULL;
1127 WCHAR *english_family, *localised_family, *StyleW;
1128 DWORD len;
1129 Family *family;
1130 Face *face;
1131 struct list *family_elem_ptr, *face_elem_ptr;
1132 FT_Error err;
1133 FT_Long face_index = 0, num_faces;
1134 #ifdef HAVE_FREETYPE_FTWINFNT_H
1135 FT_WinFNT_HeaderRec winfnt_header;
1136 #endif
1137 int i, bitmap_num, internal_leading;
1138 FONTSIGNATURE fs;
1140 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1141 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1143 #ifdef HAVE_CARBON_CARBON_H
1144 if(file && !fake_family)
1146 char **mac_list = expand_mac_font(file);
1147 if(mac_list)
1149 BOOL had_one = FALSE;
1150 char **cursor;
1151 for(cursor = mac_list; *cursor; cursor++)
1153 had_one = TRUE;
1154 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1155 HeapFree(GetProcessHeap(), 0, *cursor);
1157 HeapFree(GetProcessHeap(), 0, mac_list);
1158 if(had_one)
1159 return 1;
1162 #endif /* HAVE_CARBON_CARBON_H */
1164 do {
1165 char *family_name = fake_family;
1167 if (file)
1169 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1170 err = pFT_New_Face(library, file, face_index, &ft_face);
1171 } else
1173 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1174 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1177 if(err != 0) {
1178 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1179 return 0;
1182 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*/
1183 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1184 pFT_Done_Face(ft_face);
1185 return 0;
1188 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1189 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1190 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1191 pFT_Done_Face(ft_face);
1192 return 0;
1195 if(FT_IS_SFNT(ft_face))
1197 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1198 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1199 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1201 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1202 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1203 pFT_Done_Face(ft_face);
1204 return 0;
1207 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1208 we don't want to load these. */
1209 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1211 FT_ULong len = 0;
1213 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1215 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1216 pFT_Done_Face(ft_face);
1217 return 0;
1222 if(!ft_face->family_name || !ft_face->style_name) {
1223 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1224 pFT_Done_Face(ft_face);
1225 return 0;
1228 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1230 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1231 pFT_Done_Face(ft_face);
1232 return 0;
1235 if (target_family)
1237 localised_family = get_familyname(ft_face);
1238 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1240 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1241 HeapFree(GetProcessHeap(), 0, localised_family);
1242 num_faces = ft_face->num_faces;
1243 pFT_Done_Face(ft_face);
1244 continue;
1246 HeapFree(GetProcessHeap(), 0, localised_family);
1249 if(!family_name)
1250 family_name = ft_face->family_name;
1252 bitmap_num = 0;
1253 do {
1254 My_FT_Bitmap_Size *size = NULL;
1255 FT_ULong tmp_size;
1257 if(!FT_IS_SCALABLE(ft_face))
1258 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1260 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1261 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1262 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1264 localised_family = NULL;
1265 if(!fake_family) {
1266 localised_family = get_familyname(ft_face);
1267 if(localised_family && !strcmpW(localised_family, english_family)) {
1268 HeapFree(GetProcessHeap(), 0, localised_family);
1269 localised_family = NULL;
1273 family = NULL;
1274 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1275 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1276 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1277 break;
1278 family = NULL;
1280 if(!family) {
1281 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1282 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1283 list_init(&family->faces);
1284 list_add_tail(&font_list, &family->entry);
1286 if(localised_family) {
1287 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1288 subst->from.name = strdupW(english_family);
1289 subst->from.charset = -1;
1290 subst->to.name = strdupW(localised_family);
1291 subst->to.charset = -1;
1292 add_font_subst(&font_subst_list, subst, 0);
1295 HeapFree(GetProcessHeap(), 0, localised_family);
1296 HeapFree(GetProcessHeap(), 0, english_family);
1298 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1299 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1300 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1302 internal_leading = 0;
1303 memset(&fs, 0, sizeof(fs));
1305 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1306 if(pOS2) {
1307 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1308 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1309 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1310 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1311 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1312 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1313 if(pOS2->version == 0) {
1314 FT_UInt dummy;
1316 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1317 fs.fsCsb[0] |= FS_LATIN1;
1318 else
1319 fs.fsCsb[0] |= FS_SYMBOL;
1322 #ifdef HAVE_FREETYPE_FTWINFNT_H
1323 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1324 CHARSETINFO csi;
1325 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1326 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1327 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1328 fs = csi.fs;
1329 internal_leading = winfnt_header.internal_leading;
1331 #endif
1333 face_elem_ptr = list_head(&family->faces);
1334 while(face_elem_ptr) {
1335 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1336 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1337 if(!strcmpW(face->StyleName, StyleW) &&
1338 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1339 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1340 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1341 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1343 if(fake_family) {
1344 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1345 HeapFree(GetProcessHeap(), 0, StyleW);
1346 pFT_Done_Face(ft_face);
1347 return 1;
1349 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1350 TRACE("Original font is newer so skipping this one\n");
1351 HeapFree(GetProcessHeap(), 0, StyleW);
1352 pFT_Done_Face(ft_face);
1353 return 1;
1354 } else {
1355 TRACE("Replacing original with this one\n");
1356 list_remove(&face->entry);
1357 HeapFree(GetProcessHeap(), 0, face->file);
1358 HeapFree(GetProcessHeap(), 0, face->StyleName);
1359 HeapFree(GetProcessHeap(), 0, face);
1360 break;
1364 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1365 face->cached_enum_data = NULL;
1366 list_add_tail(&family->faces, &face->entry);
1367 face->StyleName = StyleW;
1368 if (file)
1370 face->file = strdupA(file);
1371 face->font_data_ptr = NULL;
1372 face->font_data_size = 0;
1374 else
1376 face->file = NULL;
1377 face->font_data_ptr = font_data_ptr;
1378 face->font_data_size = font_data_size;
1380 face->face_index = face_index;
1381 face->ntmFlags = 0;
1382 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1383 face->ntmFlags |= NTM_ITALIC;
1384 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1385 face->ntmFlags |= NTM_BOLD;
1386 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1387 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1388 face->family = family;
1389 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1390 face->fs = fs;
1391 memset(&face->fs_links, 0, sizeof(face->fs_links));
1393 if(FT_IS_SCALABLE(ft_face)) {
1394 memset(&face->size, 0, sizeof(face->size));
1395 face->scalable = TRUE;
1396 } else {
1397 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1398 size->height, size->width, size->size >> 6,
1399 size->x_ppem >> 6, size->y_ppem >> 6);
1400 face->size.height = size->height;
1401 face->size.width = size->width;
1402 face->size.size = size->size;
1403 face->size.x_ppem = size->x_ppem;
1404 face->size.y_ppem = size->y_ppem;
1405 face->size.internal_leading = internal_leading;
1406 face->scalable = FALSE;
1409 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1410 tmp_size = 0;
1411 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1413 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1414 face->ntmFlags |= NTM_PS_OPENTYPE;
1417 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1418 face->fs.fsCsb[0], face->fs.fsCsb[1],
1419 face->fs.fsUsb[0], face->fs.fsUsb[1],
1420 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1423 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1424 for(i = 0; i < ft_face->num_charmaps; i++) {
1425 switch(ft_face->charmaps[i]->encoding) {
1426 case FT_ENCODING_UNICODE:
1427 case FT_ENCODING_APPLE_ROMAN:
1428 face->fs.fsCsb[0] |= FS_LATIN1;
1429 break;
1430 case FT_ENCODING_MS_SYMBOL:
1431 face->fs.fsCsb[0] |= FS_SYMBOL;
1432 break;
1433 default:
1434 break;
1439 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1440 have_installed_roman_font = TRUE;
1441 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1443 num_faces = ft_face->num_faces;
1444 pFT_Done_Face(ft_face);
1445 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1446 debugstr_w(StyleW));
1447 } while(num_faces > ++face_index);
1448 return num_faces;
1451 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1453 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1456 static void DumpFontList(void)
1458 Family *family;
1459 Face *face;
1460 struct list *family_elem_ptr, *face_elem_ptr;
1462 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1463 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1464 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1465 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1466 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1467 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1468 if(!face->scalable)
1469 TRACE(" %d", face->size.height);
1470 TRACE("\n");
1473 return;
1476 /***********************************************************
1477 * The replacement list is a way to map an entire font
1478 * family onto another family. For example adding
1480 * [HKCU\Software\Wine\Fonts\Replacements]
1481 * "Wingdings"="Winedings"
1483 * would enumerate the Winedings font both as Winedings and
1484 * Wingdings. However if a real Wingdings font is present the
1485 * replacement does not take place.
1488 static void LoadReplaceList(void)
1490 HKEY hkey;
1491 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1492 LPWSTR value;
1493 LPVOID data;
1494 Family *family;
1495 Face *face;
1496 struct list *family_elem_ptr, *face_elem_ptr;
1497 CHAR familyA[400];
1499 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1500 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1502 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1503 &valuelen, &datalen, NULL, NULL);
1505 valuelen++; /* returned value doesn't include room for '\0' */
1506 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1507 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1509 dlen = datalen;
1510 vlen = valuelen;
1511 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1512 &dlen) == ERROR_SUCCESS) {
1513 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1514 /* "NewName"="Oldname" */
1515 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1517 /* Find the old family and hence all of the font files
1518 in that family */
1519 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1520 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1521 if(!strcmpiW(family->FamilyName, data)) {
1522 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1523 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1524 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1525 debugstr_w(face->StyleName), familyA);
1526 /* Now add a new entry with the new family name */
1527 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1529 break;
1532 /* reset dlen and vlen */
1533 dlen = datalen;
1534 vlen = valuelen;
1536 HeapFree(GetProcessHeap(), 0, data);
1537 HeapFree(GetProcessHeap(), 0, value);
1538 RegCloseKey(hkey);
1542 /*************************************************************
1543 * init_system_links
1545 static BOOL init_system_links(void)
1547 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1548 'W','i','n','d','o','w','s',' ','N','T','\\',
1549 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1550 'S','y','s','t','e','m','L','i','n','k',0};
1551 HKEY hkey;
1552 BOOL ret = FALSE;
1553 DWORD type, max_val, max_data, val_len, data_len, index;
1554 WCHAR *value, *data;
1555 WCHAR *entry, *next;
1556 SYSTEM_LINKS *font_link, *system_font_link;
1557 CHILD_FONT *child_font;
1558 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1559 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1560 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1561 FONTSIGNATURE fs;
1562 Family *family;
1563 Face *face;
1564 FontSubst *psub;
1566 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1568 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1569 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1570 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1571 val_len = max_val + 1;
1572 data_len = max_data;
1573 index = 0;
1574 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1576 TRACE("%s:\n", debugstr_w(value));
1578 memset(&fs, 0, sizeof(fs));
1579 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1580 psub = get_font_subst(&font_subst_list, value, -1);
1581 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1582 list_init(&font_link->links);
1583 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1585 WCHAR *face_name;
1586 CHILD_FONT *child_font;
1588 TRACE("\t%s\n", debugstr_w(entry));
1590 next = entry + strlenW(entry) + 1;
1592 face_name = strchrW(entry, ',');
1593 if(face_name)
1595 *face_name++ = 0;
1596 while(isspaceW(*face_name))
1597 face_name++;
1599 psub = get_font_subst(&font_subst_list, face_name, -1);
1600 if(psub)
1601 face_name = psub->to.name;
1603 face = find_face_from_filename(entry, face_name);
1604 if(!face)
1606 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1607 continue;
1610 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1611 child_font->face = face;
1612 child_font->font = NULL;
1613 fs.fsCsb[0] |= face->fs.fsCsb[0];
1614 fs.fsCsb[1] |= face->fs.fsCsb[1];
1615 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1616 list_add_tail(&font_link->links, &child_font->entry);
1618 family = find_family_from_name(font_link->font_name);
1619 if(family)
1621 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1623 face->fs_links = fs;
1626 list_add_tail(&system_links, &font_link->entry);
1627 val_len = max_val + 1;
1628 data_len = max_data;
1631 HeapFree(GetProcessHeap(), 0, value);
1632 HeapFree(GetProcessHeap(), 0, data);
1633 RegCloseKey(hkey);
1636 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1637 that Tahoma has */
1639 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1640 system_font_link->font_name = strdupW(System);
1641 list_init(&system_font_link->links);
1643 face = find_face_from_filename(tahoma_ttf, Tahoma);
1644 if(face)
1646 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1647 child_font->face = face;
1648 child_font->font = NULL;
1649 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1650 list_add_tail(&system_font_link->links, &child_font->entry);
1652 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1654 if(!strcmpiW(font_link->font_name, Tahoma))
1656 CHILD_FONT *font_link_entry;
1657 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1659 CHILD_FONT *new_child;
1660 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1661 new_child->face = font_link_entry->face;
1662 new_child->font = NULL;
1663 list_add_tail(&system_font_link->links, &new_child->entry);
1665 break;
1668 list_add_tail(&system_links, &system_font_link->entry);
1669 return ret;
1672 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1674 DIR *dir;
1675 struct dirent *dent;
1676 char path[MAX_PATH];
1678 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1680 dir = opendir(dirname);
1681 if(!dir) {
1682 WARN("Can't open directory %s\n", debugstr_a(dirname));
1683 return FALSE;
1685 while((dent = readdir(dir)) != NULL) {
1686 struct stat statbuf;
1688 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1689 continue;
1691 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1693 sprintf(path, "%s/%s", dirname, dent->d_name);
1695 if(stat(path, &statbuf) == -1)
1697 WARN("Can't stat %s\n", debugstr_a(path));
1698 continue;
1700 if(S_ISDIR(statbuf.st_mode))
1701 ReadFontDir(path, external_fonts);
1702 else
1703 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1705 closedir(dir);
1706 return TRUE;
1709 static void load_fontconfig_fonts(void)
1711 #ifdef SONAME_LIBFONTCONFIG
1712 void *fc_handle = NULL;
1713 FcConfig *config;
1714 FcPattern *pat;
1715 FcObjectSet *os;
1716 FcFontSet *fontset;
1717 int i, len;
1718 char *file;
1719 const char *ext;
1721 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1722 if(!fc_handle) {
1723 TRACE("Wine cannot find the fontconfig library (%s).\n",
1724 SONAME_LIBFONTCONFIG);
1725 return;
1727 #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;}
1728 LOAD_FUNCPTR(FcConfigGetCurrent);
1729 LOAD_FUNCPTR(FcFontList);
1730 LOAD_FUNCPTR(FcFontSetDestroy);
1731 LOAD_FUNCPTR(FcInit);
1732 LOAD_FUNCPTR(FcObjectSetAdd);
1733 LOAD_FUNCPTR(FcObjectSetCreate);
1734 LOAD_FUNCPTR(FcObjectSetDestroy);
1735 LOAD_FUNCPTR(FcPatternCreate);
1736 LOAD_FUNCPTR(FcPatternDestroy);
1737 LOAD_FUNCPTR(FcPatternGetBool);
1738 LOAD_FUNCPTR(FcPatternGetString);
1739 #undef LOAD_FUNCPTR
1741 if(!pFcInit()) return;
1743 config = pFcConfigGetCurrent();
1744 pat = pFcPatternCreate();
1745 os = pFcObjectSetCreate();
1746 pFcObjectSetAdd(os, FC_FILE);
1747 pFcObjectSetAdd(os, FC_SCALABLE);
1748 fontset = pFcFontList(config, pat, os);
1749 if(!fontset) return;
1750 for(i = 0; i < fontset->nfont; i++) {
1751 FcBool scalable;
1753 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1754 continue;
1755 TRACE("fontconfig: %s\n", file);
1757 /* We're just interested in OT/TT fonts for now, so this hack just
1758 picks up the scalable fonts without extensions .pf[ab] to save time
1759 loading every other font */
1761 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1763 TRACE("not scalable\n");
1764 continue;
1767 len = strlen( file );
1768 if(len < 4) continue;
1769 ext = &file[ len - 3 ];
1770 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1771 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1773 pFcFontSetDestroy(fontset);
1774 pFcObjectSetDestroy(os);
1775 pFcPatternDestroy(pat);
1776 sym_not_found:
1777 #endif
1778 return;
1781 static BOOL load_font_from_data_dir(LPCWSTR file)
1783 BOOL ret = FALSE;
1784 const char *data_dir = wine_get_data_dir();
1786 if (!data_dir) data_dir = wine_get_build_dir();
1788 if (data_dir)
1790 INT len;
1791 char *unix_name;
1793 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1795 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1797 strcpy(unix_name, data_dir);
1798 strcat(unix_name, "/fonts/");
1800 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1802 EnterCriticalSection( &freetype_cs );
1803 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1804 LeaveCriticalSection( &freetype_cs );
1805 HeapFree(GetProcessHeap(), 0, unix_name);
1807 return ret;
1810 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1812 static const WCHAR slashW[] = {'\\','\0'};
1813 BOOL ret = FALSE;
1814 WCHAR windowsdir[MAX_PATH];
1815 char *unixname;
1817 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1818 strcatW(windowsdir, fontsW);
1819 strcatW(windowsdir, slashW);
1820 strcatW(windowsdir, file);
1821 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1822 EnterCriticalSection( &freetype_cs );
1823 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1824 LeaveCriticalSection( &freetype_cs );
1825 HeapFree(GetProcessHeap(), 0, unixname);
1827 return ret;
1830 static void load_system_fonts(void)
1832 HKEY hkey;
1833 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1834 const WCHAR * const *value;
1835 DWORD dlen, type;
1836 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1837 char *unixname;
1839 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1840 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1841 strcatW(windowsdir, fontsW);
1842 for(value = SystemFontValues; *value; value++) {
1843 dlen = sizeof(data);
1844 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1845 type == REG_SZ) {
1846 BOOL added = FALSE;
1848 sprintfW(pathW, fmtW, windowsdir, data);
1849 if((unixname = wine_get_unix_file_name(pathW))) {
1850 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1851 HeapFree(GetProcessHeap(), 0, unixname);
1853 if (!added)
1854 load_font_from_data_dir(data);
1857 RegCloseKey(hkey);
1861 /*************************************************************
1863 * This adds registry entries for any externally loaded fonts
1864 * (fonts from fontconfig or FontDirs). It also deletes entries
1865 * of no longer existing fonts.
1868 static void update_reg_entries(void)
1870 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1871 LPWSTR valueW;
1872 DWORD len, len_fam;
1873 Family *family;
1874 Face *face;
1875 struct list *family_elem_ptr, *face_elem_ptr;
1876 WCHAR *file;
1877 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1878 static const WCHAR spaceW[] = {' ', '\0'};
1879 char *path;
1881 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1882 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1883 ERR("Can't create Windows font reg key\n");
1884 goto end;
1887 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1888 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1889 ERR("Can't create Windows font reg key\n");
1890 goto end;
1893 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1894 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1895 ERR("Can't create external font reg key\n");
1896 goto end;
1899 /* enumerate the fonts and add external ones to the two keys */
1901 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1902 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1903 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1904 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1905 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1906 if(!face->external) continue;
1907 len = len_fam;
1908 if(strcmpiW(face->StyleName, RegularW))
1909 len = len_fam + strlenW(face->StyleName) + 1;
1910 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1911 strcpyW(valueW, family->FamilyName);
1912 if(len != len_fam) {
1913 strcatW(valueW, spaceW);
1914 strcatW(valueW, face->StyleName);
1916 strcatW(valueW, TrueType);
1918 file = wine_get_dos_file_name(face->file);
1919 if(file)
1920 len = strlenW(file) + 1;
1921 else
1923 if((path = strrchr(face->file, '/')) == NULL)
1924 path = face->file;
1925 else
1926 path++;
1927 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1929 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1930 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1932 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1933 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1934 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1936 HeapFree(GetProcessHeap(), 0, file);
1937 HeapFree(GetProcessHeap(), 0, valueW);
1940 end:
1941 if(external_key) RegCloseKey(external_key);
1942 if(win9x_key) RegCloseKey(win9x_key);
1943 if(winnt_key) RegCloseKey(winnt_key);
1944 return;
1947 static void delete_external_font_keys(void)
1949 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1950 DWORD dlen, vlen, datalen, valuelen, i, type;
1951 LPWSTR valueW;
1952 LPVOID data;
1954 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1955 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1956 ERR("Can't create Windows font reg key\n");
1957 goto end;
1960 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1961 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1962 ERR("Can't create Windows font reg key\n");
1963 goto end;
1966 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
1967 ERR("Can't create external font reg key\n");
1968 goto end;
1971 /* Delete all external fonts added last time */
1973 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1974 &valuelen, &datalen, NULL, NULL);
1975 valuelen++; /* returned value doesn't include room for '\0' */
1976 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1977 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1979 dlen = datalen * sizeof(WCHAR);
1980 vlen = valuelen;
1981 i = 0;
1982 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
1983 &dlen) == ERROR_SUCCESS) {
1985 RegDeleteValueW(winnt_key, valueW);
1986 RegDeleteValueW(win9x_key, valueW);
1987 /* reset dlen and vlen */
1988 dlen = datalen;
1989 vlen = valuelen;
1991 HeapFree(GetProcessHeap(), 0, data);
1992 HeapFree(GetProcessHeap(), 0, valueW);
1994 /* Delete the old external fonts key */
1995 RegCloseKey(external_key);
1996 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1998 end:
1999 if(win9x_key) RegCloseKey(win9x_key);
2000 if(winnt_key) RegCloseKey(winnt_key);
2003 /*************************************************************
2004 * WineEngAddFontResourceEx
2007 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2009 INT ret = 0;
2010 if (ft_handle) /* do it only if we have freetype up and running */
2012 char *unixname;
2014 if(flags)
2015 FIXME("Ignoring flags %x\n", flags);
2017 if((unixname = wine_get_unix_file_name(file)))
2019 EnterCriticalSection( &freetype_cs );
2020 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2021 LeaveCriticalSection( &freetype_cs );
2022 HeapFree(GetProcessHeap(), 0, unixname);
2024 if (!ret && !strchrW(file, '\\')) {
2025 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2026 ret = load_font_from_winfonts_dir(file);
2027 if (!ret) {
2028 /* Try in datadir/fonts (or builddir/fonts),
2029 * needed for Magic the Gathering Online
2031 ret = load_font_from_data_dir(file);
2035 return ret;
2038 /*************************************************************
2039 * WineEngAddFontMemResourceEx
2042 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2044 if (ft_handle) /* do it only if we have freetype up and running */
2046 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2048 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2049 memcpy(pFontCopy, pbFont, cbFont);
2051 EnterCriticalSection( &freetype_cs );
2052 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2053 LeaveCriticalSection( &freetype_cs );
2055 if (*pcFonts == 0)
2057 TRACE("AddFontToList failed\n");
2058 HeapFree(GetProcessHeap(), 0, pFontCopy);
2059 return NULL;
2061 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2062 * For now return something unique but quite random
2064 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2065 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2068 *pcFonts = 0;
2069 return 0;
2072 /*************************************************************
2073 * WineEngRemoveFontResourceEx
2076 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2078 FIXME(":stub\n");
2079 return TRUE;
2082 static const struct nls_update_font_list
2084 UINT ansi_cp, oem_cp;
2085 const char *oem, *fixed, *system;
2086 const char *courier, *serif, *small, *sserif;
2087 /* these are for font substitute */
2088 const char *shelldlg, *tmsrmn;
2089 } nls_update_font_list[] =
2091 /* Latin 1 (United States) */
2092 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2093 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2094 "Tahoma","Times New Roman",
2096 /* Latin 1 (Multilingual) */
2097 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2098 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2099 "Tahoma","Times New Roman", /* FIXME unverified */
2101 /* Eastern Europe */
2102 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2103 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2104 "Tahoma","Times New Roman", /* FIXME unverified */
2106 /* Cyrillic */
2107 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2108 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2109 "Tahoma","Times New Roman", /* FIXME unverified */
2111 /* Greek */
2112 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2113 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2114 "Tahoma","Times New Roman", /* FIXME unverified */
2116 /* Turkish */
2117 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2118 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2119 "Tahoma","Times New Roman", /* FIXME unverified */
2121 /* Hebrew */
2122 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2123 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2124 "Tahoma","Times New Roman", /* FIXME unverified */
2126 /* Arabic */
2127 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2128 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2129 "Tahoma","Times New Roman", /* FIXME unverified */
2131 /* Baltic */
2132 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2133 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2134 "Tahoma","Times New Roman", /* FIXME unverified */
2136 /* Vietnamese */
2137 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2138 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2139 "Tahoma","Times New Roman", /* FIXME unverified */
2141 /* Thai */
2142 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2143 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2144 "Tahoma","Times New Roman", /* FIXME unverified */
2146 /* Japanese */
2147 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2148 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2149 "MS UI Gothic","MS Serif",
2151 /* Chinese Simplified */
2152 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2153 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2154 "Tahoma", "Times New Roman", /* FIXME unverified */
2156 /* Korean */
2157 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2158 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2159 "Gulim", "Batang",
2161 /* Chinese Traditional */
2162 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2163 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2164 "PMingLiU", "MingLiU",
2168 static inline HKEY create_fonts_NT_registry_key(void)
2170 HKEY hkey = 0;
2172 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2173 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2174 return hkey;
2177 static inline HKEY create_fonts_9x_registry_key(void)
2179 HKEY hkey = 0;
2181 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2182 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2183 return hkey;
2186 static inline HKEY create_config_fonts_registry_key(void)
2188 HKEY hkey = 0;
2190 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2191 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2192 return hkey;
2195 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2197 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2198 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2199 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2200 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2203 static void update_font_info(void)
2205 char buf[40], cpbuf[40];
2206 DWORD len, type;
2207 HKEY hkey = 0;
2208 UINT i, ansi_cp = 0, oem_cp = 0;
2210 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2211 return;
2213 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2214 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2215 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2216 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2217 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2219 /* Setup Default_Fallback usage */
2220 if (ansi_cp == 932)
2221 use_default_fallback = TRUE;
2223 len = sizeof(buf);
2224 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2226 if (!strcmp( buf, cpbuf )) /* already set correctly */
2228 RegCloseKey(hkey);
2229 return;
2231 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2233 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2235 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2236 RegCloseKey(hkey);
2238 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2240 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2241 nls_update_font_list[i].oem_cp == oem_cp)
2243 HKEY hkey;
2245 hkey = create_config_fonts_registry_key();
2246 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2247 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2248 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2249 RegCloseKey(hkey);
2251 hkey = create_fonts_NT_registry_key();
2252 add_font_list(hkey, &nls_update_font_list[i]);
2253 RegCloseKey(hkey);
2255 hkey = create_fonts_9x_registry_key();
2256 add_font_list(hkey, &nls_update_font_list[i]);
2257 RegCloseKey(hkey);
2259 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2261 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2262 strlen(nls_update_font_list[i].shelldlg)+1);
2263 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2264 strlen(nls_update_font_list[i].tmsrmn)+1);
2265 RegCloseKey(hkey);
2267 return;
2270 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2274 static BOOL init_freetype(void)
2276 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2277 if(!ft_handle) {
2278 WINE_MESSAGE(
2279 "Wine cannot find the FreeType font library. To enable Wine to\n"
2280 "use TrueType fonts please install a version of FreeType greater than\n"
2281 "or equal to 2.0.5.\n"
2282 "http://www.freetype.org\n");
2283 return FALSE;
2286 #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;}
2288 LOAD_FUNCPTR(FT_Vector_Unit)
2289 LOAD_FUNCPTR(FT_Done_Face)
2290 LOAD_FUNCPTR(FT_Get_Char_Index)
2291 LOAD_FUNCPTR(FT_Get_Module)
2292 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2293 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2294 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2295 LOAD_FUNCPTR(FT_Init_FreeType)
2296 LOAD_FUNCPTR(FT_Load_Glyph)
2297 LOAD_FUNCPTR(FT_Matrix_Multiply)
2298 LOAD_FUNCPTR(FT_MulFix)
2299 LOAD_FUNCPTR(FT_New_Face)
2300 LOAD_FUNCPTR(FT_New_Memory_Face)
2301 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2302 LOAD_FUNCPTR(FT_Outline_Transform)
2303 LOAD_FUNCPTR(FT_Outline_Translate)
2304 LOAD_FUNCPTR(FT_Select_Charmap)
2305 LOAD_FUNCPTR(FT_Set_Charmap)
2306 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2307 LOAD_FUNCPTR(FT_Vector_Transform)
2309 #undef LOAD_FUNCPTR
2310 /* Don't warn if these ones are missing */
2311 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2312 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2313 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2314 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2315 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2316 #ifdef HAVE_FREETYPE_FTWINFNT_H
2317 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2318 #endif
2319 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2320 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2321 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2322 <= 2.0.3 has FT_Sqrt64 */
2323 goto sym_not_found;
2326 if(pFT_Init_FreeType(&library) != 0) {
2327 ERR("Can't init FreeType library\n");
2328 wine_dlclose(ft_handle, NULL, 0);
2329 ft_handle = NULL;
2330 return FALSE;
2332 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2333 if (pFT_Library_Version)
2334 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2336 if (FT_Version.major<=0)
2338 FT_Version.major=2;
2339 FT_Version.minor=0;
2340 FT_Version.patch=5;
2342 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2343 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2344 ((FT_Version.minor << 8) & 0x00ff00) |
2345 ((FT_Version.patch ) & 0x0000ff);
2347 return TRUE;
2349 sym_not_found:
2350 WINE_MESSAGE(
2351 "Wine cannot find certain functions that it needs inside the FreeType\n"
2352 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2353 "FreeType to at least version 2.0.5.\n"
2354 "http://www.freetype.org\n");
2355 wine_dlclose(ft_handle, NULL, 0);
2356 ft_handle = NULL;
2357 return FALSE;
2360 /*************************************************************
2361 * WineEngInit
2363 * Initialize FreeType library and create a list of available faces
2365 BOOL WineEngInit(void)
2367 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2368 static const WCHAR pathW[] = {'P','a','t','h',0};
2369 HKEY hkey;
2370 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2371 LPVOID data;
2372 WCHAR windowsdir[MAX_PATH];
2373 char *unixname;
2374 HANDLE font_mutex;
2375 const char *data_dir;
2377 TRACE("\n");
2379 /* update locale dependent font info in registry */
2380 update_font_info();
2382 if(!init_freetype()) return FALSE;
2384 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2385 ERR("Failed to create font mutex\n");
2386 return FALSE;
2388 WaitForSingleObject(font_mutex, INFINITE);
2390 delete_external_font_keys();
2392 /* load the system bitmap fonts */
2393 load_system_fonts();
2395 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2396 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2397 strcatW(windowsdir, fontsW);
2398 if((unixname = wine_get_unix_file_name(windowsdir)))
2400 ReadFontDir(unixname, FALSE);
2401 HeapFree(GetProcessHeap(), 0, unixname);
2404 /* load the system truetype fonts */
2405 data_dir = wine_get_data_dir();
2406 if (!data_dir) data_dir = wine_get_build_dir();
2407 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2408 strcpy(unixname, data_dir);
2409 strcat(unixname, "/fonts/");
2410 ReadFontDir(unixname, TRUE);
2411 HeapFree(GetProcessHeap(), 0, unixname);
2414 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2415 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2416 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2417 will skip these. */
2418 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2419 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2420 &hkey) == ERROR_SUCCESS) {
2421 LPWSTR valueW;
2422 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2423 &valuelen, &datalen, NULL, NULL);
2425 valuelen++; /* returned value doesn't include room for '\0' */
2426 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2427 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2428 if (valueW && data)
2430 dlen = datalen * sizeof(WCHAR);
2431 vlen = valuelen;
2432 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2433 &dlen) == ERROR_SUCCESS) {
2434 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2436 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2438 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2439 HeapFree(GetProcessHeap(), 0, unixname);
2442 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2444 WCHAR pathW[MAX_PATH];
2445 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2446 BOOL added = FALSE;
2448 sprintfW(pathW, fmtW, windowsdir, data);
2449 if((unixname = wine_get_unix_file_name(pathW)))
2451 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2452 HeapFree(GetProcessHeap(), 0, unixname);
2454 if (!added)
2455 load_font_from_data_dir(data);
2457 /* reset dlen and vlen */
2458 dlen = datalen;
2459 vlen = valuelen;
2462 HeapFree(GetProcessHeap(), 0, data);
2463 HeapFree(GetProcessHeap(), 0, valueW);
2464 RegCloseKey(hkey);
2467 load_fontconfig_fonts();
2469 /* then look in any directories that we've specified in the config file */
2470 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2471 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2473 DWORD len;
2474 LPWSTR valueW;
2475 LPSTR valueA, ptr;
2477 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2479 len += sizeof(WCHAR);
2480 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2481 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2483 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2484 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2485 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2486 TRACE( "got font path %s\n", debugstr_a(valueA) );
2487 ptr = valueA;
2488 while (ptr)
2490 LPSTR next = strchr( ptr, ':' );
2491 if (next) *next++ = 0;
2492 ReadFontDir( ptr, TRUE );
2493 ptr = next;
2495 HeapFree( GetProcessHeap(), 0, valueA );
2497 HeapFree( GetProcessHeap(), 0, valueW );
2499 RegCloseKey(hkey);
2502 DumpFontList();
2503 LoadSubstList();
2504 DumpSubstList();
2505 LoadReplaceList();
2506 update_reg_entries();
2508 init_system_links();
2510 ReleaseMutex(font_mutex);
2511 return TRUE;
2515 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2517 TT_OS2 *pOS2;
2518 TT_HoriHeader *pHori;
2520 LONG ppem;
2522 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2523 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2525 if(height == 0) height = 16;
2527 /* Calc. height of EM square:
2529 * For +ve lfHeight we have
2530 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2531 * Re-arranging gives:
2532 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2534 * For -ve lfHeight we have
2535 * |lfHeight| = ppem
2536 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2537 * with il = winAscent + winDescent - units_per_em]
2541 if(height > 0) {
2542 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2543 ppem = ft_face->units_per_EM * height /
2544 (pHori->Ascender - pHori->Descender);
2545 else
2546 ppem = ft_face->units_per_EM * height /
2547 (pOS2->usWinAscent + pOS2->usWinDescent);
2549 else
2550 ppem = -height;
2552 return ppem;
2555 static struct font_mapping *map_font_file( const char *name )
2557 struct font_mapping *mapping;
2558 struct stat st;
2559 int fd;
2561 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2562 if (fstat( fd, &st ) == -1) goto error;
2564 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2566 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2568 mapping->refcount++;
2569 close( fd );
2570 return mapping;
2573 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2574 goto error;
2576 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2577 close( fd );
2579 if (mapping->data == MAP_FAILED)
2581 HeapFree( GetProcessHeap(), 0, mapping );
2582 return NULL;
2584 mapping->refcount = 1;
2585 mapping->dev = st.st_dev;
2586 mapping->ino = st.st_ino;
2587 mapping->size = st.st_size;
2588 list_add_tail( &mappings_list, &mapping->entry );
2589 return mapping;
2591 error:
2592 close( fd );
2593 return NULL;
2596 static void unmap_font_file( struct font_mapping *mapping )
2598 if (!--mapping->refcount)
2600 list_remove( &mapping->entry );
2601 munmap( mapping->data, mapping->size );
2602 HeapFree( GetProcessHeap(), 0, mapping );
2606 static LONG load_VDMX(GdiFont*, LONG);
2608 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2610 FT_Error err;
2611 FT_Face ft_face;
2612 void *data_ptr;
2613 DWORD data_size;
2615 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2617 if (face->file)
2619 if (!(font->mapping = map_font_file( face->file )))
2621 WARN("failed to map %s\n", debugstr_a(face->file));
2622 return 0;
2624 data_ptr = font->mapping->data;
2625 data_size = font->mapping->size;
2627 else
2629 data_ptr = face->font_data_ptr;
2630 data_size = face->font_data_size;
2633 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2634 if(err) {
2635 ERR("FT_New_Face rets %d\n", err);
2636 return 0;
2639 /* set it here, as load_VDMX needs it */
2640 font->ft_face = ft_face;
2642 if(FT_IS_SCALABLE(ft_face)) {
2643 /* load the VDMX table if we have one */
2644 font->ppem = load_VDMX(font, height);
2645 if(font->ppem == 0)
2646 font->ppem = calc_ppem_for_height(ft_face, height);
2648 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2649 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2650 } else {
2651 font->ppem = height;
2652 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2653 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2655 return ft_face;
2659 static int get_nearest_charset(Face *face, int *cp)
2661 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2662 a single face with the requested charset. The idea is to check if
2663 the selected font supports the current ANSI codepage, if it does
2664 return the corresponding charset, else return the first charset */
2666 CHARSETINFO csi;
2667 int acp = GetACP(), i;
2668 DWORD fs0;
2670 *cp = acp;
2671 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2672 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2673 return csi.ciCharset;
2675 for(i = 0; i < 32; i++) {
2676 fs0 = 1L << i;
2677 if(face->fs.fsCsb[0] & fs0) {
2678 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2679 *cp = csi.ciACP;
2680 return csi.ciCharset;
2682 else
2683 FIXME("TCI failing on %x\n", fs0);
2687 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2688 face->fs.fsCsb[0], face->file);
2689 *cp = acp;
2690 return DEFAULT_CHARSET;
2693 static GdiFont *alloc_font(void)
2695 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2696 ret->gmsize = 1;
2697 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2698 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2699 ret->potm = NULL;
2700 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2701 ret->total_kern_pairs = (DWORD)-1;
2702 ret->kern_pairs = NULL;
2703 list_init(&ret->hfontlist);
2704 list_init(&ret->child_fonts);
2705 return ret;
2708 static void free_font(GdiFont *font)
2710 struct list *cursor, *cursor2;
2711 int i;
2713 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2715 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2716 struct list *first_hfont;
2717 HFONTLIST *hfontlist;
2718 list_remove(cursor);
2719 if(child->font)
2721 first_hfont = list_head(&child->font->hfontlist);
2722 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2723 DeleteObject(hfontlist->hfont);
2724 HeapFree(GetProcessHeap(), 0, hfontlist);
2725 free_font(child->font);
2727 HeapFree(GetProcessHeap(), 0, child);
2730 if (font->ft_face) pFT_Done_Face(font->ft_face);
2731 if (font->mapping) unmap_font_file( font->mapping );
2732 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2733 HeapFree(GetProcessHeap(), 0, font->potm);
2734 HeapFree(GetProcessHeap(), 0, font->name);
2735 for (i = 0; i < font->gmsize; i++)
2736 HeapFree(GetProcessHeap(),0,font->gm[i]);
2737 HeapFree(GetProcessHeap(), 0, font->gm);
2738 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2739 HeapFree(GetProcessHeap(), 0, font);
2743 /*************************************************************
2744 * load_VDMX
2746 * load the vdmx entry for the specified height
2749 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2750 ( ( (FT_ULong)_x4 << 24 ) | \
2751 ( (FT_ULong)_x3 << 16 ) | \
2752 ( (FT_ULong)_x2 << 8 ) | \
2753 (FT_ULong)_x1 )
2755 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2757 typedef struct {
2758 BYTE bCharSet;
2759 BYTE xRatio;
2760 BYTE yStartRatio;
2761 BYTE yEndRatio;
2762 } Ratios;
2764 typedef struct {
2765 WORD recs;
2766 BYTE startsz;
2767 BYTE endsz;
2768 } VDMX_group;
2770 static LONG load_VDMX(GdiFont *font, LONG height)
2772 WORD hdr[3], tmp;
2773 VDMX_group group;
2774 BYTE devXRatio, devYRatio;
2775 USHORT numRecs, numRatios;
2776 DWORD result, offset = -1;
2777 LONG ppem = 0;
2778 int i;
2780 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2782 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2783 return ppem;
2785 /* FIXME: need the real device aspect ratio */
2786 devXRatio = 1;
2787 devYRatio = 1;
2789 numRecs = GET_BE_WORD(hdr[1]);
2790 numRatios = GET_BE_WORD(hdr[2]);
2792 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2793 for(i = 0; i < numRatios; i++) {
2794 Ratios ratio;
2796 offset = (3 * 2) + (i * sizeof(Ratios));
2797 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2798 offset = -1;
2800 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2802 if((ratio.xRatio == 0 &&
2803 ratio.yStartRatio == 0 &&
2804 ratio.yEndRatio == 0) ||
2805 (devXRatio == ratio.xRatio &&
2806 devYRatio >= ratio.yStartRatio &&
2807 devYRatio <= ratio.yEndRatio))
2809 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2810 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2811 offset = GET_BE_WORD(tmp);
2812 break;
2816 if(offset == -1) {
2817 FIXME("No suitable ratio found\n");
2818 return ppem;
2821 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2822 USHORT recs;
2823 BYTE startsz, endsz;
2824 WORD *vTable;
2826 recs = GET_BE_WORD(group.recs);
2827 startsz = group.startsz;
2828 endsz = group.endsz;
2830 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2832 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2833 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2834 if(result == GDI_ERROR) {
2835 FIXME("Failed to retrieve vTable\n");
2836 goto end;
2839 if(height > 0) {
2840 for(i = 0; i < recs; i++) {
2841 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2842 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2843 ppem = GET_BE_WORD(vTable[i * 3]);
2845 if(yMax + -yMin == height) {
2846 font->yMax = yMax;
2847 font->yMin = yMin;
2848 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2849 break;
2851 if(yMax + -yMin > height) {
2852 if(--i < 0) {
2853 ppem = 0;
2854 goto end; /* failed */
2856 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2857 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2858 ppem = GET_BE_WORD(vTable[i * 3]);
2859 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2860 break;
2863 if(!font->yMax) {
2864 ppem = 0;
2865 TRACE("ppem not found for height %d\n", height);
2867 } else {
2868 ppem = -height;
2869 if(ppem < startsz || ppem > endsz)
2870 goto end;
2872 for(i = 0; i < recs; i++) {
2873 USHORT yPelHeight;
2874 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2876 if(yPelHeight > ppem)
2877 break; /* failed */
2879 if(yPelHeight == ppem) {
2880 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2881 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2882 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2883 break;
2887 end:
2888 HeapFree(GetProcessHeap(), 0, vTable);
2891 return ppem;
2894 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2896 if(font->font_desc.hash != fd->hash) return TRUE;
2897 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2898 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2899 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2900 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2903 static void calc_hash(FONT_DESC *pfd)
2905 DWORD hash = 0, *ptr, two_chars;
2906 WORD *pwc;
2907 unsigned int i;
2909 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2910 hash ^= *ptr;
2911 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2912 hash ^= *ptr;
2913 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2914 two_chars = *ptr;
2915 pwc = (WCHAR *)&two_chars;
2916 if(!*pwc) break;
2917 *pwc = toupperW(*pwc);
2918 pwc++;
2919 *pwc = toupperW(*pwc);
2920 hash ^= two_chars;
2921 if(!*pwc) break;
2923 hash ^= !pfd->can_use_bitmap;
2924 pfd->hash = hash;
2925 return;
2928 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2930 GdiFont *ret;
2931 FONT_DESC fd;
2932 HFONTLIST *hflist;
2933 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2935 fd.lf = *plf;
2936 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2937 fd.can_use_bitmap = can_use_bitmap;
2938 calc_hash(&fd);
2940 /* try the in-use list */
2941 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2942 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2943 if(!fontcmp(ret, &fd)) {
2944 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2945 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2946 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2947 if(hflist->hfont == hfont)
2948 return ret;
2950 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2951 hflist->hfont = hfont;
2952 list_add_head(&ret->hfontlist, &hflist->entry);
2953 return ret;
2957 /* then the unused list */
2958 font_elem_ptr = list_head(&unused_gdi_font_list);
2959 while(font_elem_ptr) {
2960 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2961 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2962 if(!fontcmp(ret, &fd)) {
2963 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2964 assert(list_empty(&ret->hfontlist));
2965 TRACE("Found %p in unused list\n", ret);
2966 list_remove(&ret->entry);
2967 list_add_head(&gdi_font_list, &ret->entry);
2968 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2969 hflist->hfont = hfont;
2970 list_add_head(&ret->hfontlist, &hflist->entry);
2971 return ret;
2974 return NULL;
2978 /*************************************************************
2979 * create_child_font_list
2981 static BOOL create_child_font_list(GdiFont *font)
2983 BOOL ret = FALSE;
2984 SYSTEM_LINKS *font_link;
2985 CHILD_FONT *font_link_entry, *new_child;
2987 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2989 if(!strcmpW(font_link->font_name, font->name))
2991 TRACE("found entry in system list\n");
2992 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2994 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2995 new_child->face = font_link_entry->face;
2996 new_child->font = NULL;
2997 list_add_tail(&font->child_fonts, &new_child->entry);
2998 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3000 ret = TRUE;
3001 break;
3005 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3006 * Sans Serif. This is how asian windows get default fallbacks for fonts
3008 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3009 font->charset != OEM_CHARSET &&
3010 strcmpW(font->name,szDefaultFallbackLink) != 0)
3011 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3013 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3015 TRACE("found entry in default fallback list\n");
3016 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3018 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3019 new_child->face = font_link_entry->face;
3020 new_child->font = NULL;
3021 list_add_tail(&font->child_fonts, &new_child->entry);
3022 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3024 ret = TRUE;
3025 break;
3029 return ret;
3032 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3034 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3036 if (pFT_Set_Charmap)
3038 FT_Int i;
3039 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3041 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3043 for (i = 0; i < ft_face->num_charmaps; i++)
3045 if (ft_face->charmaps[i]->encoding == encoding)
3047 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3048 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3050 switch (ft_face->charmaps[i]->platform_id)
3052 default:
3053 cmap_def = ft_face->charmaps[i];
3054 break;
3055 case 0: /* Apple Unicode */
3056 cmap0 = ft_face->charmaps[i];
3057 break;
3058 case 1: /* Macintosh */
3059 cmap1 = ft_face->charmaps[i];
3060 break;
3061 case 2: /* ISO */
3062 cmap2 = ft_face->charmaps[i];
3063 break;
3064 case 3: /* Microsoft */
3065 cmap3 = ft_face->charmaps[i];
3066 break;
3070 if (cmap3) /* prefer Microsoft cmap table */
3071 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3072 else if (cmap1)
3073 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3074 else if (cmap2)
3075 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3076 else if (cmap0)
3077 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3078 else if (cmap_def)
3079 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3081 return ft_err == FT_Err_Ok;
3084 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3087 /*************************************************************
3088 * WineEngCreateFontInstance
3091 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3093 GdiFont *ret;
3094 Face *face, *best, *best_bitmap;
3095 Family *family, *last_resort_family;
3096 struct list *family_elem_ptr, *face_elem_ptr;
3097 INT height, width = 0;
3098 unsigned int score = 0, new_score;
3099 signed int diff = 0, newdiff;
3100 BOOL bd, it, can_use_bitmap;
3101 LOGFONTW lf;
3102 CHARSETINFO csi;
3103 HFONTLIST *hflist;
3105 EnterCriticalSection( &freetype_cs );
3107 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3109 struct list *first_hfont = list_head(&ret->hfontlist);
3110 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3111 if(hflist->hfont == hfont)
3113 LeaveCriticalSection( &freetype_cs );
3114 return ret;
3118 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3120 LeaveCriticalSection( &freetype_cs );
3121 return NULL;
3123 lf.lfWidth = abs(lf.lfWidth);
3125 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3127 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3128 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3129 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3130 lf.lfEscapement);
3132 /* check the cache first */
3133 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3134 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3135 LeaveCriticalSection( &freetype_cs );
3136 return ret;
3139 TRACE("not in cache\n");
3140 if(list_empty(&font_list)) /* No fonts installed */
3142 TRACE("No fonts installed\n");
3143 LeaveCriticalSection( &freetype_cs );
3144 return NULL;
3146 if(!have_installed_roman_font)
3148 TRACE("No roman font installed\n");
3149 LeaveCriticalSection( &freetype_cs );
3150 return NULL;
3153 ret = alloc_font();
3155 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3156 ret->font_desc.lf = lf;
3157 ret->font_desc.can_use_bitmap = can_use_bitmap;
3158 calc_hash(&ret->font_desc);
3159 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3160 hflist->hfont = hfont;
3161 list_add_head(&ret->hfontlist, &hflist->entry);
3164 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3165 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3166 original value lfCharSet. Note this is a special case for
3167 Symbol and doesn't happen at least for "Wingdings*" */
3169 if(!strcmpiW(lf.lfFaceName, SymbolW))
3170 lf.lfCharSet = SYMBOL_CHARSET;
3172 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3173 switch(lf.lfCharSet) {
3174 case DEFAULT_CHARSET:
3175 csi.fs.fsCsb[0] = 0;
3176 break;
3177 default:
3178 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3179 csi.fs.fsCsb[0] = 0;
3180 break;
3184 family = NULL;
3185 if(lf.lfFaceName[0] != '\0') {
3186 FontSubst *psub;
3187 SYSTEM_LINKS *font_link;
3188 CHILD_FONT *font_link_entry;
3189 LPWSTR FaceName = lf.lfFaceName;
3192 * Check for a leading '@' this signals that the font is being
3193 * requested in tategaki mode (vertical writing substitution) but
3194 * does not affect the fontface that is to be selected.
3196 if (lf.lfFaceName[0]=='@')
3197 FaceName = &lf.lfFaceName[1];
3199 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3201 if(psub) {
3202 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3203 debugstr_w(psub->to.name));
3204 strcpyW(FaceName, psub->to.name);
3207 /* We want a match on name and charset or just name if
3208 charset was DEFAULT_CHARSET. If the latter then
3209 we fixup the returned charset later in get_nearest_charset
3210 where we'll either use the charset of the current ansi codepage
3211 or if that's unavailable the first charset that the font supports.
3213 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3214 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3215 if(!strcmpiW(family->FamilyName, FaceName)) {
3216 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3217 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3218 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3219 if(face->scalable || can_use_bitmap)
3220 goto found;
3226 * Try check the SystemLink list first for a replacement font.
3227 * We may find good replacements there.
3229 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3231 if(!strcmpiW(font_link->font_name, FaceName))
3233 TRACE("found entry in system list\n");
3234 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3236 face = font_link_entry->face;
3237 family = face->family;
3238 if(csi.fs.fsCsb[0] &
3239 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3241 if(face->scalable || can_use_bitmap)
3242 goto found;
3249 /* If requested charset was DEFAULT_CHARSET then try using charset
3250 corresponding to the current ansi codepage */
3251 if(!csi.fs.fsCsb[0]) {
3252 INT acp = GetACP();
3253 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3254 FIXME("TCI failed on codepage %d\n", acp);
3255 csi.fs.fsCsb[0] = 0;
3256 } else
3257 lf.lfCharSet = csi.ciCharset;
3260 /* Face families are in the top 4 bits of lfPitchAndFamily,
3261 so mask with 0xF0 before testing */
3263 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3264 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3265 strcpyW(lf.lfFaceName, defFixed);
3266 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3267 strcpyW(lf.lfFaceName, defSerif);
3268 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3269 strcpyW(lf.lfFaceName, defSans);
3270 else
3271 strcpyW(lf.lfFaceName, defSans);
3272 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3273 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3274 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3275 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3276 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3277 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3278 if(face->scalable || can_use_bitmap)
3279 goto found;
3284 last_resort_family = NULL;
3285 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3286 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3287 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3288 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3289 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3290 if(face->scalable)
3291 goto found;
3292 if(can_use_bitmap && !last_resort_family)
3293 last_resort_family = family;
3298 if(last_resort_family) {
3299 family = last_resort_family;
3300 csi.fs.fsCsb[0] = 0;
3301 goto found;
3304 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3305 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3306 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3307 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3308 if(face->scalable) {
3309 csi.fs.fsCsb[0] = 0;
3310 WARN("just using first face for now\n");
3311 goto found;
3313 if(can_use_bitmap && !last_resort_family)
3314 last_resort_family = family;
3317 if(!last_resort_family) {
3318 FIXME("can't find a single appropriate font - bailing\n");
3319 free_font(ret);
3320 LeaveCriticalSection( &freetype_cs );
3321 return NULL;
3324 WARN("could only find a bitmap font - this will probably look awful!\n");
3325 family = last_resort_family;
3326 csi.fs.fsCsb[0] = 0;
3328 found:
3329 it = lf.lfItalic ? 1 : 0;
3330 bd = lf.lfWeight > 550 ? 1 : 0;
3332 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3333 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3335 face = best = best_bitmap = NULL;
3336 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3338 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3340 BOOL italic, bold;
3342 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3343 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3344 new_score = (italic ^ it) + (bold ^ bd);
3345 if(!best || new_score <= score)
3347 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3348 italic, bold, it, bd);
3349 score = new_score;
3350 best = face;
3351 if(best->scalable && score == 0) break;
3352 if(!best->scalable)
3354 if(height > 0)
3355 newdiff = height - (signed int)(best->size.height);
3356 else
3357 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3358 if(!best_bitmap || new_score < score ||
3359 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3361 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3362 diff = newdiff;
3363 best_bitmap = best;
3364 if(score == 0 && diff == 0) break;
3370 if(best)
3371 face = best->scalable ? best : best_bitmap;
3372 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3373 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3375 ret->fs = face->fs;
3377 if(csi.fs.fsCsb[0]) {
3378 ret->charset = lf.lfCharSet;
3379 ret->codepage = csi.ciACP;
3381 else
3382 ret->charset = get_nearest_charset(face, &ret->codepage);
3384 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3385 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3387 ret->aveWidth = height ? lf.lfWidth : 0;
3389 if(!face->scalable) {
3390 /* Windows uses integer scaling factors for bitmap fonts */
3391 INT scale, scaled_height;
3393 if (height != 0) height = diff;
3394 height += face->size.height;
3396 scale = (height + face->size.height - 1) / face->size.height;
3397 scaled_height = scale * face->size.height;
3398 /* XP allows not more than 10% deviation */
3399 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3400 ret->scale_y = scale;
3402 width = face->size.x_ppem >> 6;
3403 height = face->size.y_ppem >> 6;
3405 else
3406 ret->scale_y = 1.0;
3407 TRACE("font scale y: %f\n", ret->scale_y);
3409 ret->ft_face = OpenFontFace(ret, face, width, height);
3411 if (!ret->ft_face)
3413 free_font( ret );
3414 LeaveCriticalSection( &freetype_cs );
3415 return 0;
3418 ret->ntmFlags = face->ntmFlags;
3420 if (ret->charset == SYMBOL_CHARSET &&
3421 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3422 /* No ops */
3424 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3425 /* No ops */
3427 else {
3428 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3431 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3432 ret->name = strdupW(family->FamilyName);
3433 ret->underline = lf.lfUnderline ? 0xff : 0;
3434 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3435 create_child_font_list(ret);
3437 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3439 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3440 if (length != GDI_ERROR)
3442 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3443 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3444 TRACE("Loaded GSUB table of %i bytes\n",length);
3448 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3450 list_add_head(&gdi_font_list, &ret->entry);
3451 LeaveCriticalSection( &freetype_cs );
3452 return ret;
3455 static void dump_gdi_font_list(void)
3457 GdiFont *gdiFont;
3458 struct list *elem_ptr;
3460 TRACE("---------- gdiFont Cache ----------\n");
3461 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3462 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3463 TRACE("gdiFont=%p %s %d\n",
3464 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3467 TRACE("---------- Unused gdiFont Cache ----------\n");
3468 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3469 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3470 TRACE("gdiFont=%p %s %d\n",
3471 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3475 /*************************************************************
3476 * WineEngDestroyFontInstance
3478 * free the gdiFont associated with this handle
3481 BOOL WineEngDestroyFontInstance(HFONT handle)
3483 GdiFont *gdiFont;
3484 HFONTLIST *hflist;
3485 BOOL ret = FALSE;
3486 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3487 int i = 0;
3489 EnterCriticalSection( &freetype_cs );
3491 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3493 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3494 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3495 if(hflist->hfont == handle)
3497 TRACE("removing child font %p from child list\n", gdiFont);
3498 list_remove(&gdiFont->entry);
3499 LeaveCriticalSection( &freetype_cs );
3500 return TRUE;
3504 TRACE("destroying hfont=%p\n", handle);
3505 if(TRACE_ON(font))
3506 dump_gdi_font_list();
3508 font_elem_ptr = list_head(&gdi_font_list);
3509 while(font_elem_ptr) {
3510 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3511 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3513 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3514 while(hfontlist_elem_ptr) {
3515 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3516 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3517 if(hflist->hfont == handle) {
3518 list_remove(&hflist->entry);
3519 HeapFree(GetProcessHeap(), 0, hflist);
3520 ret = TRUE;
3523 if(list_empty(&gdiFont->hfontlist)) {
3524 TRACE("Moving to Unused list\n");
3525 list_remove(&gdiFont->entry);
3526 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3531 font_elem_ptr = list_head(&unused_gdi_font_list);
3532 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3533 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3534 while(font_elem_ptr) {
3535 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3536 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3537 TRACE("freeing %p\n", gdiFont);
3538 list_remove(&gdiFont->entry);
3539 free_font(gdiFont);
3541 LeaveCriticalSection( &freetype_cs );
3542 return ret;
3545 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3546 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3548 GdiFont *font;
3549 LONG width, height;
3551 if (face->cached_enum_data)
3553 TRACE("Cached\n");
3554 *pelf = face->cached_enum_data->elf;
3555 *pntm = face->cached_enum_data->ntm;
3556 *ptype = face->cached_enum_data->type;
3557 return;
3560 font = alloc_font();
3562 if(face->scalable) {
3563 height = 100;
3564 width = 0;
3565 } else {
3566 height = face->size.y_ppem >> 6;
3567 width = face->size.x_ppem >> 6;
3569 font->scale_y = 1.0;
3571 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3573 free_font(font);
3574 return;
3577 font->name = strdupW(face->family->FamilyName);
3578 font->ntmFlags = face->ntmFlags;
3580 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3582 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3584 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3586 lstrcpynW(pelf->elfLogFont.lfFaceName,
3587 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3588 LF_FACESIZE);
3589 lstrcpynW(pelf->elfFullName,
3590 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3591 LF_FULLFACESIZE);
3592 lstrcpynW(pelf->elfStyle,
3593 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3594 LF_FACESIZE);
3596 else
3598 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3600 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3602 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3603 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3604 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3607 pntm->ntmTm.ntmFlags = face->ntmFlags;
3608 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3609 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3610 pntm->ntmFontSig = face->fs;
3612 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3614 pelf->elfLogFont.lfEscapement = 0;
3615 pelf->elfLogFont.lfOrientation = 0;
3616 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3617 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3618 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3619 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3620 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3621 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3622 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3623 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3624 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3625 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3626 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3628 *ptype = 0;
3629 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3630 *ptype |= TRUETYPE_FONTTYPE;
3631 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3632 *ptype |= DEVICE_FONTTYPE;
3633 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3634 *ptype |= RASTER_FONTTYPE;
3636 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3637 if (face->cached_enum_data)
3639 face->cached_enum_data->elf = *pelf;
3640 face->cached_enum_data->ntm = *pntm;
3641 face->cached_enum_data->type = *ptype;
3644 free_font(font);
3647 /*************************************************************
3648 * WineEngEnumFonts
3651 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3653 Family *family;
3654 Face *face;
3655 struct list *family_elem_ptr, *face_elem_ptr;
3656 ENUMLOGFONTEXW elf;
3657 NEWTEXTMETRICEXW ntm;
3658 DWORD type;
3659 FONTSIGNATURE fs;
3660 CHARSETINFO csi;
3661 LOGFONTW lf;
3662 int i;
3664 if (!plf)
3666 lf.lfCharSet = DEFAULT_CHARSET;
3667 lf.lfPitchAndFamily = 0;
3668 lf.lfFaceName[0] = 0;
3669 plf = &lf;
3672 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3674 EnterCriticalSection( &freetype_cs );
3675 if(plf->lfFaceName[0]) {
3676 FontSubst *psub;
3677 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3679 if(psub) {
3680 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3681 debugstr_w(psub->to.name));
3682 lf = *plf;
3683 strcpyW(lf.lfFaceName, psub->to.name);
3684 plf = &lf;
3687 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3688 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3689 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3690 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3691 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3692 GetEnumStructs(face, &elf, &ntm, &type);
3693 for(i = 0; i < 32; i++) {
3694 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3695 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3696 strcpyW(elf.elfScript, OEM_DOSW);
3697 i = 32; /* break out of loop */
3698 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3699 continue;
3700 else {
3701 fs.fsCsb[0] = 1L << i;
3702 fs.fsCsb[1] = 0;
3703 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3704 TCI_SRCFONTSIG))
3705 csi.ciCharset = DEFAULT_CHARSET;
3706 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3707 if(csi.ciCharset != DEFAULT_CHARSET) {
3708 elf.elfLogFont.lfCharSet =
3709 ntm.ntmTm.tmCharSet = csi.ciCharset;
3710 if(ElfScriptsW[i])
3711 strcpyW(elf.elfScript, ElfScriptsW[i]);
3712 else
3713 FIXME("Unknown elfscript for bit %d\n", i);
3716 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3717 debugstr_w(elf.elfLogFont.lfFaceName),
3718 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3719 csi.ciCharset, type, debugstr_w(elf.elfScript),
3720 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3721 ntm.ntmTm.ntmFlags);
3722 /* release section before callback (FIXME) */
3723 LeaveCriticalSection( &freetype_cs );
3724 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3725 EnterCriticalSection( &freetype_cs );
3730 } else {
3731 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3732 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3733 face_elem_ptr = list_head(&family->faces);
3734 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3735 GetEnumStructs(face, &elf, &ntm, &type);
3736 for(i = 0; i < 32; i++) {
3737 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3738 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3739 strcpyW(elf.elfScript, OEM_DOSW);
3740 i = 32; /* break out of loop */
3741 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3742 continue;
3743 else {
3744 fs.fsCsb[0] = 1L << i;
3745 fs.fsCsb[1] = 0;
3746 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3747 TCI_SRCFONTSIG))
3748 csi.ciCharset = DEFAULT_CHARSET;
3749 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3750 if(csi.ciCharset != DEFAULT_CHARSET) {
3751 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3752 csi.ciCharset;
3753 if(ElfScriptsW[i])
3754 strcpyW(elf.elfScript, ElfScriptsW[i]);
3755 else
3756 FIXME("Unknown elfscript for bit %d\n", i);
3759 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3760 debugstr_w(elf.elfLogFont.lfFaceName),
3761 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3762 csi.ciCharset, type, debugstr_w(elf.elfScript),
3763 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3764 ntm.ntmTm.ntmFlags);
3765 /* release section before callback (FIXME) */
3766 LeaveCriticalSection( &freetype_cs );
3767 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3768 EnterCriticalSection( &freetype_cs );
3772 LeaveCriticalSection( &freetype_cs );
3773 return 1;
3776 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3778 pt->x.value = vec->x >> 6;
3779 pt->x.fract = (vec->x & 0x3f) << 10;
3780 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3781 pt->y.value = vec->y >> 6;
3782 pt->y.fract = (vec->y & 0x3f) << 10;
3783 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3784 return;
3787 /***************************************************
3788 * According to the MSDN documentation on WideCharToMultiByte,
3789 * certain codepages cannot set the default_used parameter.
3790 * This returns TRUE if the codepage can set that parameter, false else
3791 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3793 static BOOL codepage_sets_default_used(UINT codepage)
3795 switch (codepage)
3797 case CP_UTF7:
3798 case CP_UTF8:
3799 case CP_SYMBOL:
3800 return FALSE;
3801 default:
3802 return TRUE;
3807 * GSUB Table handling functions
3810 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3812 const GSUB_CoverageFormat1* cf1;
3814 cf1 = (GSUB_CoverageFormat1*)table;
3816 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3818 int count = GET_BE_WORD(cf1->GlyphCount);
3819 int i;
3820 TRACE("Coverage Format 1, %i glyphs\n",count);
3821 for (i = 0; i < count; i++)
3822 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3823 return i;
3824 return -1;
3826 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3828 const GSUB_CoverageFormat2* cf2;
3829 int i;
3830 int count;
3831 cf2 = (GSUB_CoverageFormat2*)cf1;
3833 count = GET_BE_WORD(cf2->RangeCount);
3834 TRACE("Coverage Format 2, %i ranges\n",count);
3835 for (i = 0; i < count; i++)
3837 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3838 return -1;
3839 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3840 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3842 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3843 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3846 return -1;
3848 else
3849 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3851 return -1;
3854 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3856 const GSUB_ScriptList *script;
3857 const GSUB_Script *deflt = NULL;
3858 int i;
3859 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3861 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3862 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3864 const GSUB_Script *scr;
3865 int offset;
3867 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3868 scr = (GSUB_Script*)((LPBYTE)script + offset);
3870 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3871 return scr;
3872 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3873 deflt = scr;
3875 return deflt;
3878 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3880 int i;
3881 int offset;
3882 const GSUB_LangSys *Lang;
3884 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3886 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3888 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3889 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3891 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3892 return Lang;
3894 offset = GET_BE_WORD(script->DefaultLangSys);
3895 if (offset)
3897 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3898 return Lang;
3900 return NULL;
3903 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3905 int i;
3906 const GSUB_FeatureList *feature;
3907 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3909 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
3910 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3912 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3913 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3915 const GSUB_Feature *feat;
3916 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3917 return feat;
3920 return NULL;
3923 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3925 int i;
3926 int offset;
3927 const GSUB_LookupList *lookup;
3928 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3930 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3931 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3933 const GSUB_LookupTable *look;
3934 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3935 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3936 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3937 if (GET_BE_WORD(look->LookupType) != 1)
3938 FIXME("We only handle SubType 1\n");
3939 else
3941 int j;
3943 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3945 const GSUB_SingleSubstFormat1 *ssf1;
3946 offset = GET_BE_WORD(look->SubTable[j]);
3947 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3948 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3950 int offset = GET_BE_WORD(ssf1->Coverage);
3951 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
3952 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
3954 TRACE(" Glyph 0x%x ->",glyph);
3955 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
3956 TRACE(" 0x%x\n",glyph);
3959 else
3961 const GSUB_SingleSubstFormat2 *ssf2;
3962 INT index;
3963 INT offset;
3965 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
3966 offset = GET_BE_WORD(ssf1->Coverage);
3967 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
3968 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
3969 TRACE(" Coverage index %i\n",index);
3970 if (index != -1)
3972 TRACE(" Glyph is 0x%x ->",glyph);
3973 glyph = GET_BE_WORD(ssf2->Substitute[index]);
3974 TRACE("0x%x\n",glyph);
3980 return glyph;
3983 static const char* get_opentype_script(const GdiFont *font)
3986 * I am not sure if this is the correct way to generate our script tag
3989 switch (font->charset)
3991 case ANSI_CHARSET: return "latn";
3992 case BALTIC_CHARSET: return "latn"; /* ?? */
3993 case CHINESEBIG5_CHARSET: return "hani";
3994 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
3995 case GB2312_CHARSET: return "hani";
3996 case GREEK_CHARSET: return "grek";
3997 case HANGUL_CHARSET: return "hang";
3998 case RUSSIAN_CHARSET: return "cyrl";
3999 case SHIFTJIS_CHARSET: return "kana";
4000 case TURKISH_CHARSET: return "latn"; /* ?? */
4001 case VIETNAMESE_CHARSET: return "latn";
4002 case JOHAB_CHARSET: return "latn"; /* ?? */
4003 case ARABIC_CHARSET: return "arab";
4004 case HEBREW_CHARSET: return "hebr";
4005 case THAI_CHARSET: return "thai";
4006 default: return "latn";
4010 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4012 const GSUB_Header *header;
4013 const GSUB_Script *script;
4014 const GSUB_LangSys *language;
4015 const GSUB_Feature *feature;
4017 if (!font->GSUB_Table)
4018 return glyph;
4020 header = font->GSUB_Table;
4022 script = GSUB_get_script_table(header, get_opentype_script(font));
4023 if (!script)
4025 TRACE("Script not found\n");
4026 return glyph;
4028 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4029 if (!language)
4031 TRACE("Language not found\n");
4032 return glyph;
4034 feature = GSUB_get_feature(header, language, "vrt2");
4035 if (!feature)
4036 feature = GSUB_get_feature(header, language, "vert");
4037 if (!feature)
4039 TRACE("vrt2/vert feature not found\n");
4040 return glyph;
4042 return GSUB_apply_feature(header, feature, glyph);
4045 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4047 FT_UInt glyphId;
4049 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4050 WCHAR wc = (WCHAR)glyph;
4051 BOOL default_used;
4052 BOOL *default_used_pointer;
4053 FT_UInt ret;
4054 char buf;
4055 default_used_pointer = NULL;
4056 default_used = FALSE;
4057 if (codepage_sets_default_used(font->codepage))
4058 default_used_pointer = &default_used;
4059 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4060 ret = 0;
4061 else
4062 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4063 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4064 return get_GSUB_vert_glyph(font,ret);
4067 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
4068 glyph = glyph + 0xf000;
4069 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4070 return get_GSUB_vert_glyph(font,glyphId);
4073 /*************************************************************
4074 * WineEngGetGlyphIndices
4077 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4078 LPWORD pgi, DWORD flags)
4080 int i;
4081 int default_char = -1;
4083 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4085 for(i = 0; i < count; i++)
4087 pgi[i] = get_glyph_index(font, lpstr[i]);
4088 if (pgi[i] == 0)
4090 if (default_char == -1)
4092 if (FT_IS_SFNT(font->ft_face))
4094 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4095 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4097 else
4099 TEXTMETRICW textm;
4100 WineEngGetTextMetrics(font, &textm);
4101 default_char = textm.tmDefaultChar;
4104 pgi[i] = default_char;
4107 return count;
4110 /*************************************************************
4111 * WineEngGetGlyphOutline
4113 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4114 * except that the first parameter is the HWINEENGFONT of the font in
4115 * question rather than an HDC.
4118 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4119 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4120 const MAT2* lpmat)
4122 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4123 FT_Face ft_face = incoming_font->ft_face;
4124 GdiFont *font = incoming_font;
4125 FT_UInt glyph_index;
4126 DWORD width, height, pitch, needed = 0;
4127 FT_Bitmap ft_bitmap;
4128 FT_Error err;
4129 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4130 FT_Angle angle = 0;
4131 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4132 float widthRatio = 1.0;
4133 FT_Matrix transMat = identityMat;
4134 BOOL needsTransform = FALSE;
4135 BOOL tategaki = (font->GSUB_Table != NULL);
4136 UINT original_index;
4139 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4140 buflen, buf, lpmat);
4142 EnterCriticalSection( &freetype_cs );
4144 if(format & GGO_GLYPH_INDEX) {
4145 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4146 original_index = glyph;
4147 format &= ~GGO_GLYPH_INDEX;
4148 } else {
4149 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4150 ft_face = font->ft_face;
4151 original_index = glyph_index;
4154 /* tategaki never appears to happen to lower glyph index */
4155 if (glyph_index < TATEGAKI_LOWER_BOUND )
4156 tategaki = FALSE;
4158 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4159 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4160 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4161 font->gmsize * sizeof(GM*));
4162 } else {
4163 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4164 *lpgm = FONT_GM(font,original_index)->gm;
4165 LeaveCriticalSection( &freetype_cs );
4166 return 1; /* FIXME */
4170 if (!font->gm[original_index / GM_BLOCK_SIZE])
4171 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4173 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4174 load_flags |= FT_LOAD_NO_BITMAP;
4176 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4178 if(err) {
4179 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4180 LeaveCriticalSection( &freetype_cs );
4181 return GDI_ERROR;
4184 /* Scaling factor */
4185 if (font->aveWidth && font->potm)
4187 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4188 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4190 else
4191 widthRatio = font->scale_y;
4193 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4194 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4196 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4197 lsb = left >> 6;
4198 bbx = (right - left) >> 6;
4200 /* Scaling transform */
4201 if(font->aveWidth) {
4202 FT_Matrix scaleMat;
4203 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4204 scaleMat.xy = 0;
4205 scaleMat.yx = 0;
4206 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4208 pFT_Matrix_Multiply(&scaleMat, &transMat);
4209 needsTransform = TRUE;
4212 /* Slant transform */
4213 if (font->fake_italic) {
4214 FT_Matrix slantMat;
4216 slantMat.xx = (1 << 16);
4217 slantMat.xy = ((1 << 16) >> 2);
4218 slantMat.yx = 0;
4219 slantMat.yy = (1 << 16);
4220 pFT_Matrix_Multiply(&slantMat, &transMat);
4221 needsTransform = TRUE;
4224 /* Rotation transform */
4225 if(font->orientation && !tategaki) {
4226 FT_Matrix rotationMat;
4227 FT_Vector vecAngle;
4228 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4229 pFT_Vector_Unit(&vecAngle, angle);
4230 rotationMat.xx = vecAngle.x;
4231 rotationMat.xy = -vecAngle.y;
4232 rotationMat.yx = -rotationMat.xy;
4233 rotationMat.yy = rotationMat.xx;
4235 pFT_Matrix_Multiply(&rotationMat, &transMat);
4236 needsTransform = TRUE;
4239 /* Extra transformation specified by caller */
4240 if (lpmat) {
4241 FT_Matrix extraMat;
4242 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4243 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4244 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4245 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4246 pFT_Matrix_Multiply(&extraMat, &transMat);
4247 needsTransform = TRUE;
4250 if(!needsTransform) {
4251 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4252 bottom = (ft_face->glyph->metrics.horiBearingY -
4253 ft_face->glyph->metrics.height) & -64;
4254 lpgm->gmCellIncX = adv;
4255 lpgm->gmCellIncY = 0;
4256 } else {
4257 INT xc, yc;
4258 FT_Vector vec;
4259 for(xc = 0; xc < 2; xc++) {
4260 for(yc = 0; yc < 2; yc++) {
4261 vec.x = (ft_face->glyph->metrics.horiBearingX +
4262 xc * ft_face->glyph->metrics.width);
4263 vec.y = ft_face->glyph->metrics.horiBearingY -
4264 yc * ft_face->glyph->metrics.height;
4265 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4266 pFT_Vector_Transform(&vec, &transMat);
4267 if(xc == 0 && yc == 0) {
4268 left = right = vec.x;
4269 top = bottom = vec.y;
4270 } else {
4271 if(vec.x < left) left = vec.x;
4272 else if(vec.x > right) right = vec.x;
4273 if(vec.y < bottom) bottom = vec.y;
4274 else if(vec.y > top) top = vec.y;
4278 left = left & -64;
4279 right = (right + 63) & -64;
4280 bottom = bottom & -64;
4281 top = (top + 63) & -64;
4283 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4284 vec.x = ft_face->glyph->metrics.horiAdvance;
4285 vec.y = 0;
4286 pFT_Vector_Transform(&vec, &transMat);
4287 lpgm->gmCellIncX = (vec.x+63) >> 6;
4288 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4290 lpgm->gmBlackBoxX = (right - left) >> 6;
4291 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4292 lpgm->gmptGlyphOrigin.x = left >> 6;
4293 lpgm->gmptGlyphOrigin.y = top >> 6;
4295 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4297 FONT_GM(font,original_index)->gm = *lpgm;
4298 FONT_GM(font,original_index)->adv = adv;
4299 FONT_GM(font,original_index)->lsb = lsb;
4300 FONT_GM(font,original_index)->bbx = bbx;
4301 FONT_GM(font,original_index)->init = TRUE;
4304 if(format == GGO_METRICS)
4306 LeaveCriticalSection( &freetype_cs );
4307 return 1; /* FIXME */
4310 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4311 TRACE("loaded a bitmap\n");
4312 LeaveCriticalSection( &freetype_cs );
4313 return GDI_ERROR;
4316 switch(format) {
4317 case GGO_BITMAP:
4318 width = lpgm->gmBlackBoxX;
4319 height = lpgm->gmBlackBoxY;
4320 pitch = ((width + 31) >> 5) << 2;
4321 needed = pitch * height;
4323 if(!buf || !buflen) break;
4325 switch(ft_face->glyph->format) {
4326 case ft_glyph_format_bitmap:
4328 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4329 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4330 INT h = ft_face->glyph->bitmap.rows;
4331 while(h--) {
4332 memcpy(dst, src, w);
4333 src += ft_face->glyph->bitmap.pitch;
4334 dst += pitch;
4336 break;
4339 case ft_glyph_format_outline:
4340 ft_bitmap.width = width;
4341 ft_bitmap.rows = height;
4342 ft_bitmap.pitch = pitch;
4343 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4344 ft_bitmap.buffer = buf;
4346 if(needsTransform) {
4347 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4350 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4352 /* Note: FreeType will only set 'black' bits for us. */
4353 memset(buf, 0, needed);
4354 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4355 break;
4357 default:
4358 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4359 LeaveCriticalSection( &freetype_cs );
4360 return GDI_ERROR;
4362 break;
4364 case GGO_GRAY2_BITMAP:
4365 case GGO_GRAY4_BITMAP:
4366 case GGO_GRAY8_BITMAP:
4367 case WINE_GGO_GRAY16_BITMAP:
4369 unsigned int mult, row, col;
4370 BYTE *start, *ptr;
4372 width = lpgm->gmBlackBoxX;
4373 height = lpgm->gmBlackBoxY;
4374 pitch = (width + 3) / 4 * 4;
4375 needed = pitch * height;
4377 if(!buf || !buflen) break;
4379 switch(ft_face->glyph->format) {
4380 case ft_glyph_format_bitmap:
4382 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4383 INT h = ft_face->glyph->bitmap.rows;
4384 INT x;
4385 while(h--) {
4386 for(x = 0; x < pitch; x++)
4387 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4388 src += ft_face->glyph->bitmap.pitch;
4389 dst += pitch;
4391 LeaveCriticalSection( &freetype_cs );
4392 return needed;
4394 case ft_glyph_format_outline:
4396 ft_bitmap.width = width;
4397 ft_bitmap.rows = height;
4398 ft_bitmap.pitch = pitch;
4399 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4400 ft_bitmap.buffer = buf;
4402 if(needsTransform)
4403 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4405 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4407 memset(ft_bitmap.buffer, 0, buflen);
4409 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4411 if(format == GGO_GRAY2_BITMAP)
4412 mult = 4;
4413 else if(format == GGO_GRAY4_BITMAP)
4414 mult = 16;
4415 else if(format == GGO_GRAY8_BITMAP)
4416 mult = 64;
4417 else /* format == WINE_GGO_GRAY16_BITMAP */
4419 LeaveCriticalSection( &freetype_cs );
4420 return needed;
4422 break;
4424 default:
4425 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4426 LeaveCriticalSection( &freetype_cs );
4427 return GDI_ERROR;
4430 start = buf;
4431 for(row = 0; row < height; row++) {
4432 ptr = start;
4433 for(col = 0; col < width; col++, ptr++) {
4434 *ptr = (((int)*ptr) * mult + 128) / 256;
4436 start += pitch;
4438 break;
4441 case GGO_NATIVE:
4443 int contour, point = 0, first_pt;
4444 FT_Outline *outline = &ft_face->glyph->outline;
4445 TTPOLYGONHEADER *pph;
4446 TTPOLYCURVE *ppc;
4447 DWORD pph_start, cpfx, type;
4449 if(buflen == 0) buf = NULL;
4451 if (needsTransform && buf) {
4452 pFT_Outline_Transform(outline, &transMat);
4455 for(contour = 0; contour < outline->n_contours; contour++) {
4456 pph_start = needed;
4457 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4458 first_pt = point;
4459 if(buf) {
4460 pph->dwType = TT_POLYGON_TYPE;
4461 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4463 needed += sizeof(*pph);
4464 point++;
4465 while(point <= outline->contours[contour]) {
4466 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4467 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4468 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4469 cpfx = 0;
4470 do {
4471 if(buf)
4472 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4473 cpfx++;
4474 point++;
4475 } while(point <= outline->contours[contour] &&
4476 (outline->tags[point] & FT_Curve_Tag_On) ==
4477 (outline->tags[point-1] & FT_Curve_Tag_On));
4478 /* At the end of a contour Windows adds the start point, but
4479 only for Beziers */
4480 if(point > outline->contours[contour] &&
4481 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4482 if(buf)
4483 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4484 cpfx++;
4485 } else if(point <= outline->contours[contour] &&
4486 outline->tags[point] & FT_Curve_Tag_On) {
4487 /* add closing pt for bezier */
4488 if(buf)
4489 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4490 cpfx++;
4491 point++;
4493 if(buf) {
4494 ppc->wType = type;
4495 ppc->cpfx = cpfx;
4497 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4499 if(buf)
4500 pph->cb = needed - pph_start;
4502 break;
4504 case GGO_BEZIER:
4506 /* Convert the quadratic Beziers to cubic Beziers.
4507 The parametric eqn for a cubic Bezier is, from PLRM:
4508 r(t) = at^3 + bt^2 + ct + r0
4509 with the control points:
4510 r1 = r0 + c/3
4511 r2 = r1 + (c + b)/3
4512 r3 = r0 + c + b + a
4514 A quadratic Beizer has the form:
4515 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4517 So equating powers of t leads to:
4518 r1 = 2/3 p1 + 1/3 p0
4519 r2 = 2/3 p1 + 1/3 p2
4520 and of course r0 = p0, r3 = p2
4523 int contour, point = 0, first_pt;
4524 FT_Outline *outline = &ft_face->glyph->outline;
4525 TTPOLYGONHEADER *pph;
4526 TTPOLYCURVE *ppc;
4527 DWORD pph_start, cpfx, type;
4528 FT_Vector cubic_control[4];
4529 if(buflen == 0) buf = NULL;
4531 if (needsTransform && buf) {
4532 pFT_Outline_Transform(outline, &transMat);
4535 for(contour = 0; contour < outline->n_contours; contour++) {
4536 pph_start = needed;
4537 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4538 first_pt = point;
4539 if(buf) {
4540 pph->dwType = TT_POLYGON_TYPE;
4541 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4543 needed += sizeof(*pph);
4544 point++;
4545 while(point <= outline->contours[contour]) {
4546 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4547 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4548 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4549 cpfx = 0;
4550 do {
4551 if(type == TT_PRIM_LINE) {
4552 if(buf)
4553 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4554 cpfx++;
4555 point++;
4556 } else {
4557 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4558 so cpfx = 3n */
4560 /* FIXME: Possible optimization in endpoint calculation
4561 if there are two consecutive curves */
4562 cubic_control[0] = outline->points[point-1];
4563 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4564 cubic_control[0].x += outline->points[point].x + 1;
4565 cubic_control[0].y += outline->points[point].y + 1;
4566 cubic_control[0].x >>= 1;
4567 cubic_control[0].y >>= 1;
4569 if(point+1 > outline->contours[contour])
4570 cubic_control[3] = outline->points[first_pt];
4571 else {
4572 cubic_control[3] = outline->points[point+1];
4573 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4574 cubic_control[3].x += outline->points[point].x + 1;
4575 cubic_control[3].y += outline->points[point].y + 1;
4576 cubic_control[3].x >>= 1;
4577 cubic_control[3].y >>= 1;
4580 /* r1 = 1/3 p0 + 2/3 p1
4581 r2 = 1/3 p2 + 2/3 p1 */
4582 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4583 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4584 cubic_control[2] = cubic_control[1];
4585 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4586 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4587 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4588 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4589 if(buf) {
4590 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4591 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4592 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4594 cpfx += 3;
4595 point++;
4597 } while(point <= outline->contours[contour] &&
4598 (outline->tags[point] & FT_Curve_Tag_On) ==
4599 (outline->tags[point-1] & FT_Curve_Tag_On));
4600 /* At the end of a contour Windows adds the start point,
4601 but only for Beziers and we've already done that.
4603 if(point <= outline->contours[contour] &&
4604 outline->tags[point] & FT_Curve_Tag_On) {
4605 /* This is the closing pt of a bezier, but we've already
4606 added it, so just inc point and carry on */
4607 point++;
4609 if(buf) {
4610 ppc->wType = type;
4611 ppc->cpfx = cpfx;
4613 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4615 if(buf)
4616 pph->cb = needed - pph_start;
4618 break;
4621 default:
4622 FIXME("Unsupported format %d\n", format);
4623 LeaveCriticalSection( &freetype_cs );
4624 return GDI_ERROR;
4626 LeaveCriticalSection( &freetype_cs );
4627 return needed;
4630 static BOOL get_bitmap_text_metrics(GdiFont *font)
4632 FT_Face ft_face = font->ft_face;
4633 #ifdef HAVE_FREETYPE_FTWINFNT_H
4634 FT_WinFNT_HeaderRec winfnt_header;
4635 #endif
4636 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4637 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4638 font->potm->otmSize = size;
4640 #define TM font->potm->otmTextMetrics
4641 #ifdef HAVE_FREETYPE_FTWINFNT_H
4642 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4644 TM.tmHeight = winfnt_header.pixel_height;
4645 TM.tmAscent = winfnt_header.ascent;
4646 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4647 TM.tmInternalLeading = winfnt_header.internal_leading;
4648 TM.tmExternalLeading = winfnt_header.external_leading;
4649 TM.tmAveCharWidth = winfnt_header.avg_width;
4650 TM.tmMaxCharWidth = winfnt_header.max_width;
4651 TM.tmWeight = winfnt_header.weight;
4652 TM.tmOverhang = 0;
4653 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4654 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4655 TM.tmFirstChar = winfnt_header.first_char;
4656 TM.tmLastChar = winfnt_header.last_char;
4657 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4658 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4659 TM.tmItalic = winfnt_header.italic;
4660 TM.tmUnderlined = font->underline;
4661 TM.tmStruckOut = font->strikeout;
4662 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4663 TM.tmCharSet = winfnt_header.charset;
4665 else
4666 #endif
4668 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4669 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4670 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4671 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4672 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4673 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4674 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4675 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4676 TM.tmOverhang = 0;
4677 TM.tmDigitizedAspectX = 96; /* FIXME */
4678 TM.tmDigitizedAspectY = 96; /* FIXME */
4679 TM.tmFirstChar = 1;
4680 TM.tmLastChar = 255;
4681 TM.tmDefaultChar = 32;
4682 TM.tmBreakChar = 32;
4683 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4684 TM.tmUnderlined = font->underline;
4685 TM.tmStruckOut = font->strikeout;
4686 /* NB inverted meaning of TMPF_FIXED_PITCH */
4687 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4688 TM.tmCharSet = font->charset;
4690 #undef TM
4692 return TRUE;
4696 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4698 float scale_x;
4700 if (font->aveWidth)
4702 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4703 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4705 else
4706 scale_x = font->scale_y;
4708 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4709 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4710 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4711 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4712 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4714 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4715 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4718 /*************************************************************
4719 * WineEngGetTextMetrics
4722 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4724 EnterCriticalSection( &freetype_cs );
4725 if(!font->potm) {
4726 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4727 if(!get_bitmap_text_metrics(font))
4729 LeaveCriticalSection( &freetype_cs );
4730 return FALSE;
4733 if(!font->potm)
4735 LeaveCriticalSection( &freetype_cs );
4736 return FALSE;
4738 *ptm = font->potm->otmTextMetrics;
4739 scale_font_metrics(font, ptm);
4740 LeaveCriticalSection( &freetype_cs );
4741 return TRUE;
4745 /*************************************************************
4746 * WineEngGetOutlineTextMetrics
4749 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4750 OUTLINETEXTMETRICW *potm)
4752 FT_Face ft_face = font->ft_face;
4753 UINT needed, lenfam, lensty, ret;
4754 TT_OS2 *pOS2;
4755 TT_HoriHeader *pHori;
4756 TT_Postscript *pPost;
4757 FT_Fixed x_scale, y_scale;
4758 WCHAR *family_nameW, *style_nameW;
4759 static const WCHAR spaceW[] = {' ', '\0'};
4760 char *cp;
4761 INT ascent, descent;
4763 TRACE("font=%p\n", font);
4765 if(!FT_IS_SCALABLE(ft_face))
4766 return 0;
4768 EnterCriticalSection( &freetype_cs );
4770 if(font->potm) {
4771 if(cbSize >= font->potm->otmSize)
4773 memcpy(potm, font->potm, font->potm->otmSize);
4774 scale_font_metrics(font, &potm->otmTextMetrics);
4776 LeaveCriticalSection( &freetype_cs );
4777 return font->potm->otmSize;
4781 needed = sizeof(*potm);
4783 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4784 family_nameW = strdupW(font->name);
4786 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4787 * sizeof(WCHAR);
4788 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4789 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4790 style_nameW, lensty/sizeof(WCHAR));
4792 /* These names should be read from the TT name table */
4794 /* length of otmpFamilyName */
4795 needed += lenfam;
4797 /* length of otmpFaceName */
4798 if(!strcasecmp(ft_face->style_name, "regular")) {
4799 needed += lenfam; /* just the family name */
4800 } else {
4801 needed += lenfam + lensty; /* family + " " + style */
4804 /* length of otmpStyleName */
4805 needed += lensty;
4807 /* length of otmpFullName */
4808 needed += lenfam + lensty;
4811 x_scale = ft_face->size->metrics.x_scale;
4812 y_scale = ft_face->size->metrics.y_scale;
4814 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4815 if(!pOS2) {
4816 FIXME("Can't find OS/2 table - not TT font?\n");
4817 ret = 0;
4818 goto end;
4821 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4822 if(!pHori) {
4823 FIXME("Can't find HHEA table - not TT font?\n");
4824 ret = 0;
4825 goto end;
4828 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4830 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",
4831 pOS2->usWinAscent, pOS2->usWinDescent,
4832 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4833 ft_face->ascender, ft_face->descender, ft_face->height,
4834 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4835 ft_face->bbox.yMax, ft_face->bbox.yMin);
4837 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4838 font->potm->otmSize = needed;
4840 #define TM font->potm->otmTextMetrics
4842 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4843 ascent = pHori->Ascender;
4844 descent = -pHori->Descender;
4845 } else {
4846 ascent = pOS2->usWinAscent;
4847 descent = pOS2->usWinDescent;
4850 if(font->yMax) {
4851 TM.tmAscent = font->yMax;
4852 TM.tmDescent = -font->yMin;
4853 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4854 } else {
4855 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4856 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4857 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4858 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4861 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4863 /* MSDN says:
4864 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4866 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4867 ((ascent + descent) -
4868 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4870 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4871 if (TM.tmAveCharWidth == 0) {
4872 TM.tmAveCharWidth = 1;
4874 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4875 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4876 TM.tmOverhang = 0;
4877 TM.tmDigitizedAspectX = 300;
4878 TM.tmDigitizedAspectY = 300;
4879 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4880 * symbol range to 0 - f0ff
4882 if (font->charset == SYMBOL_CHARSET)
4883 TM.tmFirstChar = 0;
4884 else
4885 TM.tmFirstChar = pOS2->usFirstCharIndex;
4886 TM.tmLastChar = pOS2->usLastCharIndex;
4887 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4888 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4889 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4890 TM.tmUnderlined = font->underline;
4891 TM.tmStruckOut = font->strikeout;
4893 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4894 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4895 (pOS2->version == 0xFFFFU ||
4896 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4897 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4898 else
4899 TM.tmPitchAndFamily = 0;
4901 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4902 case PAN_FAMILY_SCRIPT:
4903 TM.tmPitchAndFamily |= FF_SCRIPT;
4904 break;
4905 case PAN_FAMILY_DECORATIVE:
4906 case PAN_FAMILY_PICTORIAL:
4907 TM.tmPitchAndFamily |= FF_DECORATIVE;
4908 break;
4909 case PAN_FAMILY_TEXT_DISPLAY:
4910 if(TM.tmPitchAndFamily == 0) /* fixed */
4911 TM.tmPitchAndFamily = FF_MODERN;
4912 else {
4913 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4914 case PAN_SERIF_NORMAL_SANS:
4915 case PAN_SERIF_OBTUSE_SANS:
4916 case PAN_SERIF_PERP_SANS:
4917 TM.tmPitchAndFamily |= FF_SWISS;
4918 break;
4919 default:
4920 TM.tmPitchAndFamily |= FF_ROMAN;
4923 break;
4924 default:
4925 TM.tmPitchAndFamily |= FF_DONTCARE;
4928 if(FT_IS_SCALABLE(ft_face))
4929 TM.tmPitchAndFamily |= TMPF_VECTOR;
4931 if(FT_IS_SFNT(ft_face))
4933 if (font->ntmFlags & NTM_PS_OPENTYPE)
4934 TM.tmPitchAndFamily |= TMPF_DEVICE;
4935 else
4936 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4939 TM.tmCharSet = font->charset;
4940 #undef TM
4942 font->potm->otmFiller = 0;
4943 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4944 font->potm->otmfsSelection = pOS2->fsSelection;
4945 font->potm->otmfsType = pOS2->fsType;
4946 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4947 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4948 font->potm->otmItalicAngle = 0; /* POST table */
4949 font->potm->otmEMSquare = ft_face->units_per_EM;
4950 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4951 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4952 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4953 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4954 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4955 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4956 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4957 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4958 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4959 font->potm->otmMacAscent = 0; /* where do these come from ? */
4960 font->potm->otmMacDescent = 0;
4961 font->potm->otmMacLineGap = 0;
4962 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4963 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4964 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4965 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4966 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4967 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4968 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4969 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4970 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4971 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4972 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4973 if(!pPost) {
4974 font->potm->otmsUnderscoreSize = 0;
4975 font->potm->otmsUnderscorePosition = 0;
4976 } else {
4977 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4978 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4981 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4982 cp = (char*)font->potm + sizeof(*font->potm);
4983 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4984 strcpyW((WCHAR*)cp, family_nameW);
4985 cp += lenfam;
4986 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4987 strcpyW((WCHAR*)cp, style_nameW);
4988 cp += lensty;
4989 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4990 strcpyW((WCHAR*)cp, family_nameW);
4991 if(strcasecmp(ft_face->style_name, "regular")) {
4992 strcatW((WCHAR*)cp, spaceW);
4993 strcatW((WCHAR*)cp, style_nameW);
4994 cp += lenfam + lensty;
4995 } else
4996 cp += lenfam;
4997 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4998 strcpyW((WCHAR*)cp, family_nameW);
4999 strcatW((WCHAR*)cp, spaceW);
5000 strcatW((WCHAR*)cp, style_nameW);
5001 ret = needed;
5003 if(potm && needed <= cbSize)
5005 memcpy(potm, font->potm, font->potm->otmSize);
5006 scale_font_metrics(font, &potm->otmTextMetrics);
5009 end:
5010 HeapFree(GetProcessHeap(), 0, style_nameW);
5011 HeapFree(GetProcessHeap(), 0, family_nameW);
5013 LeaveCriticalSection( &freetype_cs );
5014 return ret;
5017 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5019 HFONTLIST *hfontlist;
5020 child->font = alloc_font();
5021 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5022 if(!child->font->ft_face)
5024 free_font(child->font);
5025 child->font = NULL;
5026 return FALSE;
5029 child->font->ntmFlags = child->face->ntmFlags;
5030 child->font->orientation = font->orientation;
5031 child->font->scale_y = font->scale_y;
5032 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5033 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5034 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5035 child->font->base_font = font;
5036 list_add_head(&child_font_list, &child->font->entry);
5037 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5038 return TRUE;
5041 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5043 FT_UInt g;
5044 CHILD_FONT *child_font;
5046 if(font->base_font)
5047 font = font->base_font;
5049 *linked_font = font;
5051 if((*glyph = get_glyph_index(font, c)))
5052 return TRUE;
5054 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5056 if(!child_font->font)
5057 if(!load_child_font(font, child_font))
5058 continue;
5060 if(!child_font->font->ft_face)
5061 continue;
5062 g = get_glyph_index(child_font->font, c);
5063 if(g)
5065 *glyph = g;
5066 *linked_font = child_font->font;
5067 return TRUE;
5070 return FALSE;
5073 /*************************************************************
5074 * WineEngGetCharWidth
5077 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5078 LPINT buffer)
5080 UINT c;
5081 GLYPHMETRICS gm;
5082 FT_UInt glyph_index;
5083 GdiFont *linked_font;
5085 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5087 EnterCriticalSection( &freetype_cs );
5088 for(c = firstChar; c <= lastChar; c++) {
5089 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5090 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5091 &gm, 0, NULL, NULL);
5092 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5094 LeaveCriticalSection( &freetype_cs );
5095 return TRUE;
5098 /*************************************************************
5099 * WineEngGetCharABCWidths
5102 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5103 LPABC buffer)
5105 UINT c;
5106 GLYPHMETRICS gm;
5107 FT_UInt glyph_index;
5108 GdiFont *linked_font;
5110 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5112 if(!FT_IS_SCALABLE(font->ft_face))
5113 return FALSE;
5115 EnterCriticalSection( &freetype_cs );
5117 for(c = firstChar; c <= lastChar; c++) {
5118 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5119 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5120 &gm, 0, NULL, NULL);
5121 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5122 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5123 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5124 FONT_GM(linked_font,glyph_index)->bbx;
5126 LeaveCriticalSection( &freetype_cs );
5127 return TRUE;
5130 /*************************************************************
5131 * WineEngGetCharABCWidthsI
5134 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5135 LPABC buffer)
5137 UINT c;
5138 GLYPHMETRICS gm;
5139 FT_UInt glyph_index;
5140 GdiFont *linked_font;
5142 if(!FT_HAS_HORIZONTAL(font->ft_face))
5143 return FALSE;
5145 EnterCriticalSection( &freetype_cs );
5147 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5148 if (!pgi)
5149 for(c = firstChar; c < firstChar+count; c++) {
5150 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5151 &gm, 0, NULL, NULL);
5152 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5153 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5154 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5155 - FONT_GM(linked_font,c)->bbx;
5157 else
5158 for(c = 0; c < count; c++) {
5159 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5160 &gm, 0, NULL, NULL);
5161 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5162 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5163 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5164 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5167 LeaveCriticalSection( &freetype_cs );
5168 return TRUE;
5171 /*************************************************************
5172 * WineEngGetTextExtentExPoint
5175 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5176 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5178 INT idx;
5179 INT nfit = 0, ext;
5180 GLYPHMETRICS gm;
5181 TEXTMETRICW tm;
5182 FT_UInt glyph_index;
5183 GdiFont *linked_font;
5185 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5186 max_ext, size);
5188 EnterCriticalSection( &freetype_cs );
5190 size->cx = 0;
5191 WineEngGetTextMetrics(font, &tm);
5192 size->cy = tm.tmHeight;
5194 for(idx = 0; idx < count; idx++) {
5195 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5196 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5197 &gm, 0, NULL, NULL);
5198 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5199 ext = size->cx;
5200 if (! pnfit || ext <= max_ext) {
5201 ++nfit;
5202 if (dxs)
5203 dxs[idx] = ext;
5207 if (pnfit)
5208 *pnfit = nfit;
5210 LeaveCriticalSection( &freetype_cs );
5211 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5212 return TRUE;
5215 /*************************************************************
5216 * WineEngGetTextExtentExPointI
5219 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5220 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5222 INT idx;
5223 INT nfit = 0, ext;
5224 GLYPHMETRICS gm;
5225 TEXTMETRICW tm;
5227 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5229 EnterCriticalSection( &freetype_cs );
5231 size->cx = 0;
5232 WineEngGetTextMetrics(font, &tm);
5233 size->cy = tm.tmHeight;
5235 for(idx = 0; idx < count; idx++) {
5236 WineEngGetGlyphOutline(font, indices[idx],
5237 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5238 NULL);
5239 size->cx += FONT_GM(font,indices[idx])->adv;
5240 ext = size->cx;
5241 if (! pnfit || ext <= max_ext) {
5242 ++nfit;
5243 if (dxs)
5244 dxs[idx] = ext;
5248 if (pnfit)
5249 *pnfit = nfit;
5251 LeaveCriticalSection( &freetype_cs );
5252 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5253 return TRUE;
5256 /*************************************************************
5257 * WineEngGetFontData
5260 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5261 DWORD cbData)
5263 FT_Face ft_face = font->ft_face;
5264 FT_ULong len;
5265 FT_Error err;
5267 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5268 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5269 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5271 if(!FT_IS_SFNT(ft_face))
5272 return GDI_ERROR;
5274 if(!buf || !cbData)
5275 len = 0;
5276 else
5277 len = cbData;
5279 if(table) { /* MS tags differ in endianness from FT ones */
5280 table = table >> 24 | table << 24 |
5281 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5284 /* make sure value of len is the value freetype says it needs */
5285 if(buf && len)
5287 FT_ULong needed = 0;
5288 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5289 if( !err && needed < len) len = needed;
5291 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5293 if(err) {
5294 TRACE("Can't find table %c%c%c%c\n",
5295 /* bytes were reversed */
5296 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5297 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5298 return GDI_ERROR;
5300 return len;
5303 /*************************************************************
5304 * WineEngGetTextFace
5307 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5309 if(str) {
5310 lstrcpynW(str, font->name, count);
5311 return strlenW(font->name);
5312 } else
5313 return strlenW(font->name) + 1;
5316 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5318 if (fs) *fs = font->fs;
5319 return font->charset;
5322 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5324 GdiFont *font = dc->gdiFont, *linked_font;
5325 struct list *first_hfont;
5326 BOOL ret;
5328 EnterCriticalSection( &freetype_cs );
5329 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5330 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5331 if(font == linked_font)
5332 *new_hfont = dc->hFont;
5333 else
5335 first_hfont = list_head(&linked_font->hfontlist);
5336 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5338 LeaveCriticalSection( &freetype_cs );
5339 return ret;
5342 /* Retrieve a list of supported Unicode ranges for a given font.
5343 * Can be called with NULL gs to calculate the buffer size. Returns
5344 * the number of ranges found.
5346 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5348 DWORD num_ranges = 0;
5350 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5352 FT_UInt glyph_code;
5353 FT_ULong char_code, char_code_prev;
5355 glyph_code = 0;
5356 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5358 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5359 face->num_glyphs, glyph_code, char_code);
5361 if (!glyph_code) return 0;
5363 if (gs)
5365 gs->ranges[0].wcLow = (USHORT)char_code;
5366 gs->ranges[0].cGlyphs = 0;
5367 gs->cGlyphsSupported = 0;
5370 num_ranges = 1;
5371 while (glyph_code)
5373 if (char_code < char_code_prev)
5375 ERR("expected increasing char code from FT_Get_Next_Char\n");
5376 return 0;
5378 if (char_code - char_code_prev > 1)
5380 num_ranges++;
5381 if (gs)
5383 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5384 gs->ranges[num_ranges - 1].cGlyphs = 1;
5385 gs->cGlyphsSupported++;
5388 else if (gs)
5390 gs->ranges[num_ranges - 1].cGlyphs++;
5391 gs->cGlyphsSupported++;
5393 char_code_prev = char_code;
5394 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5397 else
5398 FIXME("encoding %u not supported\n", face->charmap->encoding);
5400 return num_ranges;
5403 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5405 DWORD size = 0;
5406 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5408 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5409 if (glyphset)
5411 glyphset->cbThis = size;
5412 glyphset->cRanges = num_ranges;
5414 return size;
5417 /*************************************************************
5418 * FontIsLinked
5420 BOOL WineEngFontIsLinked(GdiFont *font)
5422 BOOL ret;
5423 EnterCriticalSection( &freetype_cs );
5424 ret = !list_empty(&font->child_fonts);
5425 LeaveCriticalSection( &freetype_cs );
5426 return ret;
5429 static BOOL is_hinting_enabled(void)
5431 /* Use the >= 2.2.0 function if available */
5432 if(pFT_Get_TrueType_Engine_Type)
5434 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5435 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5437 #ifdef FT_DRIVER_HAS_HINTER
5438 else
5440 FT_Module mod;
5442 /* otherwise if we've been compiled with < 2.2.0 headers
5443 use the internal macro */
5444 mod = pFT_Get_Module(library, "truetype");
5445 if(mod && FT_DRIVER_HAS_HINTER(mod))
5446 return TRUE;
5448 #endif
5450 return FALSE;
5453 /*************************************************************************
5454 * GetRasterizerCaps (GDI32.@)
5456 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5458 static int hinting = -1;
5460 if(hinting == -1)
5462 hinting = is_hinting_enabled();
5463 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5466 lprs->nSize = sizeof(RASTERIZER_STATUS);
5467 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5468 lprs->nLanguageID = 0;
5469 return TRUE;
5472 /*************************************************************************
5473 * Kerning support for TrueType fonts
5475 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5477 struct TT_kern_table
5479 USHORT version;
5480 USHORT nTables;
5483 struct TT_kern_subtable
5485 USHORT version;
5486 USHORT length;
5487 union
5489 USHORT word;
5490 struct
5492 USHORT horizontal : 1;
5493 USHORT minimum : 1;
5494 USHORT cross_stream: 1;
5495 USHORT override : 1;
5496 USHORT reserved1 : 4;
5497 USHORT format : 8;
5498 } bits;
5499 } coverage;
5502 struct TT_format0_kern_subtable
5504 USHORT nPairs;
5505 USHORT searchRange;
5506 USHORT entrySelector;
5507 USHORT rangeShift;
5510 struct TT_kern_pair
5512 USHORT left;
5513 USHORT right;
5514 short value;
5517 static DWORD parse_format0_kern_subtable(GdiFont *font,
5518 const struct TT_format0_kern_subtable *tt_f0_ks,
5519 const USHORT *glyph_to_char,
5520 KERNINGPAIR *kern_pair, DWORD cPairs)
5522 USHORT i, nPairs;
5523 const struct TT_kern_pair *tt_kern_pair;
5525 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5527 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5529 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5530 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5531 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5533 if (!kern_pair || !cPairs)
5534 return nPairs;
5536 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5538 nPairs = min(nPairs, cPairs);
5540 for (i = 0; i < nPairs; i++)
5542 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5543 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5544 /* this algorithm appears to better match what Windows does */
5545 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5546 if (kern_pair->iKernAmount < 0)
5548 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5549 kern_pair->iKernAmount -= font->ppem;
5551 else if (kern_pair->iKernAmount > 0)
5553 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5554 kern_pair->iKernAmount += font->ppem;
5556 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5558 TRACE("left %u right %u value %d\n",
5559 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5561 kern_pair++;
5563 TRACE("copied %u entries\n", nPairs);
5564 return nPairs;
5567 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5569 DWORD length;
5570 void *buf;
5571 const struct TT_kern_table *tt_kern_table;
5572 const struct TT_kern_subtable *tt_kern_subtable;
5573 USHORT i, nTables;
5574 USHORT *glyph_to_char;
5576 EnterCriticalSection( &freetype_cs );
5577 if (font->total_kern_pairs != (DWORD)-1)
5579 if (cPairs && kern_pair)
5581 cPairs = min(cPairs, font->total_kern_pairs);
5582 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5583 LeaveCriticalSection( &freetype_cs );
5584 return cPairs;
5586 LeaveCriticalSection( &freetype_cs );
5587 return font->total_kern_pairs;
5590 font->total_kern_pairs = 0;
5592 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5594 if (length == GDI_ERROR)
5596 TRACE("no kerning data in the font\n");
5597 LeaveCriticalSection( &freetype_cs );
5598 return 0;
5601 buf = HeapAlloc(GetProcessHeap(), 0, length);
5602 if (!buf)
5604 WARN("Out of memory\n");
5605 LeaveCriticalSection( &freetype_cs );
5606 return 0;
5609 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5611 /* build a glyph index to char code map */
5612 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5613 if (!glyph_to_char)
5615 WARN("Out of memory allocating a glyph index to char code map\n");
5616 HeapFree(GetProcessHeap(), 0, buf);
5617 LeaveCriticalSection( &freetype_cs );
5618 return 0;
5621 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5623 FT_UInt glyph_code;
5624 FT_ULong char_code;
5626 glyph_code = 0;
5627 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5629 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5630 font->ft_face->num_glyphs, glyph_code, char_code);
5632 while (glyph_code)
5634 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5636 /* FIXME: This doesn't match what Windows does: it does some fancy
5637 * things with duplicate glyph index to char code mappings, while
5638 * we just avoid overriding existing entries.
5640 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5641 glyph_to_char[glyph_code] = (USHORT)char_code;
5643 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5646 else
5648 ULONG n;
5650 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5651 for (n = 0; n <= 65535; n++)
5652 glyph_to_char[n] = (USHORT)n;
5655 tt_kern_table = buf;
5656 nTables = GET_BE_WORD(tt_kern_table->nTables);
5657 TRACE("version %u, nTables %u\n",
5658 GET_BE_WORD(tt_kern_table->version), nTables);
5660 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5662 for (i = 0; i < nTables; i++)
5664 struct TT_kern_subtable tt_kern_subtable_copy;
5666 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5667 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5668 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5670 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5671 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5672 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5674 /* According to the TrueType specification this is the only format
5675 * that will be properly interpreted by Windows and OS/2
5677 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5679 DWORD new_chunk, old_total = font->total_kern_pairs;
5681 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5682 glyph_to_char, NULL, 0);
5683 font->total_kern_pairs += new_chunk;
5685 if (!font->kern_pairs)
5686 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5687 font->total_kern_pairs * sizeof(*font->kern_pairs));
5688 else
5689 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5690 font->total_kern_pairs * sizeof(*font->kern_pairs));
5692 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5693 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5695 else
5696 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5698 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5701 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5702 HeapFree(GetProcessHeap(), 0, buf);
5704 if (cPairs && kern_pair)
5706 cPairs = min(cPairs, font->total_kern_pairs);
5707 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5708 LeaveCriticalSection( &freetype_cs );
5709 return cPairs;
5711 LeaveCriticalSection( &freetype_cs );
5712 return font->total_kern_pairs;
5715 #else /* HAVE_FREETYPE */
5717 /*************************************************************************/
5719 BOOL WineEngInit(void)
5721 return FALSE;
5723 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5725 return NULL;
5727 BOOL WineEngDestroyFontInstance(HFONT hfont)
5729 return FALSE;
5732 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5734 return 1;
5737 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5738 LPWORD pgi, DWORD flags)
5740 return GDI_ERROR;
5743 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5744 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5745 const MAT2* lpmat)
5747 ERR("called but we don't have FreeType\n");
5748 return GDI_ERROR;
5751 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5753 ERR("called but we don't have FreeType\n");
5754 return FALSE;
5757 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5758 OUTLINETEXTMETRICW *potm)
5760 ERR("called but we don't have FreeType\n");
5761 return 0;
5764 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5765 LPINT buffer)
5767 ERR("called but we don't have FreeType\n");
5768 return FALSE;
5771 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5772 LPABC buffer)
5774 ERR("called but we don't have FreeType\n");
5775 return FALSE;
5778 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5779 LPABC buffer)
5781 ERR("called but we don't have FreeType\n");
5782 return FALSE;
5785 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5786 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5788 ERR("called but we don't have FreeType\n");
5789 return FALSE;
5792 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5793 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5795 ERR("called but we don't have FreeType\n");
5796 return FALSE;
5799 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5800 DWORD cbData)
5802 ERR("called but we don't have FreeType\n");
5803 return GDI_ERROR;
5806 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5808 ERR("called but we don't have FreeType\n");
5809 return 0;
5812 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5814 FIXME(":stub\n");
5815 return 1;
5818 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5820 FIXME(":stub\n");
5821 return TRUE;
5824 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5826 FIXME(":stub\n");
5827 return NULL;
5830 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5832 FIXME(":stub\n");
5833 return DEFAULT_CHARSET;
5836 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5838 return FALSE;
5841 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5843 FIXME("(%p, %p): stub\n", font, glyphset);
5844 return 0;
5847 BOOL WineEngFontIsLinked(GdiFont *font)
5849 return FALSE;
5852 /*************************************************************************
5853 * GetRasterizerCaps (GDI32.@)
5855 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5857 lprs->nSize = sizeof(RASTERIZER_STATUS);
5858 lprs->wFlags = 0;
5859 lprs->nLanguageID = 0;
5860 return TRUE;
5863 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5865 ERR("called but we don't have FreeType\n");
5866 return 0;
5869 #endif /* HAVE_FREETYPE */