gdi32: Check for regular fonts by style instead of style name.
[wine/gsoc_dplay.git] / dlls / gdi32 / freetype.c
blob359eb6d6d39ddc6a40eeff8b76d00723c3c860a0
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 fontsW[] = {'\\','f','o','n','t','s','\0'};
364 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
365 'W','i','n','d','o','w','s','\\',
366 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
367 'F','o','n','t','s','\0'};
369 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s',' ','N','T','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
375 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
376 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
377 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
379 static const WCHAR * const SystemFontValues[4] = {
380 System_Value,
381 OEMFont_Value,
382 FixedSys_Value,
383 NULL
386 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
387 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
389 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
390 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
391 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
392 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
393 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
394 'E','u','r','o','p','e','a','n','\0'};
395 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
396 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
397 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
398 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
399 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
400 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
401 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
402 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
403 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
404 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
405 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
406 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
408 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
409 WesternW, /*00*/
410 Central_EuropeanW,
411 CyrillicW,
412 GreekW,
413 TurkishW,
414 HebrewW,
415 ArabicW,
416 BalticW,
417 VietnameseW, /*08*/
418 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
419 ThaiW,
420 JapaneseW,
421 CHINESE_GB2312W,
422 HangulW,
423 CHINESE_BIG5W,
424 Hangul_Johab_W,
425 NULL, NULL, /*23*/
426 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
427 SymbolW /*31*/
430 typedef struct {
431 WCHAR *name;
432 INT charset;
433 } NameCs;
435 typedef struct tagFontSubst {
436 struct list entry;
437 NameCs from;
438 NameCs to;
439 } FontSubst;
441 struct font_mapping
443 struct list entry;
444 int refcount;
445 dev_t dev;
446 ino_t ino;
447 void *data;
448 size_t size;
451 static struct list mappings_list = LIST_INIT( mappings_list );
453 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
455 static CRITICAL_SECTION freetype_cs;
456 static CRITICAL_SECTION_DEBUG critsect_debug =
458 0, 0, &freetype_cs,
459 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
460 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
462 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
464 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
466 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
467 static BOOL use_default_fallback = FALSE;
469 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
471 /****************************************
472 * Notes on .fon files
474 * The fonts System, FixedSys and Terminal are special. There are typically multiple
475 * versions installed for different resolutions and codepages. Windows stores which one to use
476 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
477 * Key Meaning
478 * FIXEDFON.FON FixedSys
479 * FONTS.FON System
480 * OEMFONT.FON Terminal
481 * LogPixels Current dpi set by the display control panel applet
482 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
483 * also has a LogPixels value that appears to mirror this)
485 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
486 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
487 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
488 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
489 * so that makes sense.
491 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
492 * to be mapped into the registry on Windows 2000 at least).
493 * I have
494 * woafont=app850.fon
495 * ega80woa.fon=ega80850.fon
496 * ega40woa.fon=ega40850.fon
497 * cga80woa.fon=cga80850.fon
498 * cga40woa.fon=cga40850.fon
501 /* These are all structures needed for the GSUB table */
503 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
504 #define TATEGAKI_LOWER_BOUND 0x02F1
506 typedef struct {
507 DWORD version;
508 WORD ScriptList;
509 WORD FeatureList;
510 WORD LookupList;
511 } GSUB_Header;
513 typedef struct {
514 CHAR ScriptTag[4];
515 WORD Script;
516 } GSUB_ScriptRecord;
518 typedef struct {
519 WORD ScriptCount;
520 GSUB_ScriptRecord ScriptRecord[1];
521 } GSUB_ScriptList;
523 typedef struct {
524 CHAR LangSysTag[4];
525 WORD LangSys;
526 } GSUB_LangSysRecord;
528 typedef struct {
529 WORD DefaultLangSys;
530 WORD LangSysCount;
531 GSUB_LangSysRecord LangSysRecord[1];
532 } GSUB_Script;
534 typedef struct {
535 WORD LookupOrder; /* Reserved */
536 WORD ReqFeatureIndex;
537 WORD FeatureCount;
538 WORD FeatureIndex[1];
539 } GSUB_LangSys;
541 typedef struct {
542 CHAR FeatureTag[4];
543 WORD Feature;
544 } GSUB_FeatureRecord;
546 typedef struct {
547 WORD FeatureCount;
548 GSUB_FeatureRecord FeatureRecord[1];
549 } GSUB_FeatureList;
551 typedef struct {
552 WORD FeatureParams; /* Reserved */
553 WORD LookupCount;
554 WORD LookupListIndex[1];
555 } GSUB_Feature;
557 typedef struct {
558 WORD LookupCount;
559 WORD Lookup[1];
560 } GSUB_LookupList;
562 typedef struct {
563 WORD LookupType;
564 WORD LookupFlag;
565 WORD SubTableCount;
566 WORD SubTable[1];
567 } GSUB_LookupTable;
569 typedef struct {
570 WORD CoverageFormat;
571 WORD GlyphCount;
572 WORD GlyphArray[1];
573 } GSUB_CoverageFormat1;
575 typedef struct {
576 WORD Start;
577 WORD End;
578 WORD StartCoverageIndex;
579 } GSUB_RangeRecord;
581 typedef struct {
582 WORD CoverageFormat;
583 WORD RangeCount;
584 GSUB_RangeRecord RangeRecord[1];
585 } GSUB_CoverageFormat2;
587 typedef struct {
588 WORD SubstFormat; /* = 1 */
589 WORD Coverage;
590 WORD DeltaGlyphID;
591 } GSUB_SingleSubstFormat1;
593 typedef struct {
594 WORD SubstFormat; /* = 2 */
595 WORD Coverage;
596 WORD GlyphCount;
597 WORD Substitute[1];
598 }GSUB_SingleSubstFormat2;
600 #ifdef HAVE_CARBON_CARBON_H
601 static char *find_cache_dir(void)
603 FSRef ref;
604 OSErr err;
605 static char cached_path[MAX_PATH];
606 static const char *wine = "/Wine", *fonts = "/Fonts";
608 if(*cached_path) return cached_path;
610 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
611 if(err != noErr)
613 WARN("can't create cached data folder\n");
614 return NULL;
616 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
617 if(err != noErr)
619 WARN("can't create cached data path\n");
620 *cached_path = '\0';
621 return NULL;
623 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
625 ERR("Could not create full path\n");
626 *cached_path = '\0';
627 return NULL;
629 strcat(cached_path, wine);
631 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
633 WARN("Couldn't mkdir %s\n", cached_path);
634 *cached_path = '\0';
635 return NULL;
637 strcat(cached_path, fonts);
638 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
640 WARN("Couldn't mkdir %s\n", cached_path);
641 *cached_path = '\0';
642 return NULL;
644 return cached_path;
647 /******************************************************************
648 * expand_mac_font
650 * Extracts individual TrueType font files from a Mac suitcase font
651 * and saves them into the user's caches directory (see
652 * find_cache_dir()).
653 * Returns a NULL terminated array of filenames.
655 * We do this because they are apps that try to read ttf files
656 * themselves and they don't like Mac suitcase files.
658 static char **expand_mac_font(const char *path)
660 FSRef ref;
661 SInt16 res_ref;
662 OSStatus s;
663 unsigned int idx;
664 const char *out_dir;
665 const char *filename;
666 int output_len;
667 struct {
668 char **array;
669 unsigned int size, max_size;
670 } ret;
672 TRACE("path %s\n", path);
674 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
675 if(s != noErr)
677 WARN("failed to get ref\n");
678 return NULL;
681 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
682 if(s != noErr)
684 TRACE("no data fork, so trying resource fork\n");
685 res_ref = FSOpenResFile(&ref, fsRdPerm);
686 if(res_ref == -1)
688 TRACE("unable to open resource fork\n");
689 return NULL;
693 ret.size = 0;
694 ret.max_size = 10;
695 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
696 if(!ret.array)
698 CloseResFile(res_ref);
699 return NULL;
702 out_dir = find_cache_dir();
704 filename = strrchr(path, '/');
705 if(!filename) filename = path;
706 else filename++;
708 /* output filename has the form out_dir/filename_%04x.ttf */
709 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
711 UseResFile(res_ref);
712 idx = 1;
713 while(1)
715 FamRec *fam_rec;
716 unsigned short *num_faces_ptr, num_faces, face;
717 AsscEntry *assoc;
718 Handle fond;
719 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
721 fond = Get1IndResource(fond_res, idx);
722 if(!fond) break;
723 TRACE("got fond resource %d\n", idx);
724 HLock(fond);
726 fam_rec = *(FamRec**)fond;
727 num_faces_ptr = (unsigned short *)(fam_rec + 1);
728 num_faces = GET_BE_WORD(*num_faces_ptr);
729 num_faces++;
730 assoc = (AsscEntry*)(num_faces_ptr + 1);
731 TRACE("num faces %04x\n", num_faces);
732 for(face = 0; face < num_faces; face++, assoc++)
734 Handle sfnt;
735 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
736 unsigned short size, font_id;
737 char *output;
739 size = GET_BE_WORD(assoc->fontSize);
740 font_id = GET_BE_WORD(assoc->fontID);
741 if(size != 0)
743 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
744 continue;
747 TRACE("trying to load sfnt id %04x\n", font_id);
748 sfnt = GetResource(sfnt_res, font_id);
749 if(!sfnt)
751 TRACE("can't get sfnt resource %04x\n", font_id);
752 continue;
755 output = HeapAlloc(GetProcessHeap(), 0, output_len);
756 if(output)
758 int fd;
760 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
762 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
763 if(fd != -1 || errno == EEXIST)
765 if(fd != -1)
767 unsigned char *sfnt_data;
769 HLock(sfnt);
770 sfnt_data = *(unsigned char**)sfnt;
771 write(fd, sfnt_data, GetHandleSize(sfnt));
772 HUnlock(sfnt);
773 close(fd);
775 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
777 ret.max_size *= 2;
778 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
780 ret.array[ret.size++] = output;
782 else
784 WARN("unable to create %s\n", output);
785 HeapFree(GetProcessHeap(), 0, output);
788 ReleaseResource(sfnt);
790 HUnlock(fond);
791 ReleaseResource(fond);
792 idx++;
794 CloseResFile(res_ref);
796 return ret.array;
799 #endif /* HAVE_CARBON_CARBON_H */
801 static inline BOOL is_win9x(void)
803 return GetVersion() & 0x80000000;
806 This function builds an FT_Fixed from a float. It puts the integer part
807 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
808 It fails if the integer part of the float number is greater than SHORT_MAX.
810 static inline FT_Fixed FT_FixedFromFloat(float f)
812 short value = f;
813 unsigned short fract = (f - value) * 0xFFFF;
814 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
818 This function builds an FT_Fixed from a FIXED. It simply put f.value
819 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
821 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
823 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
827 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
829 Family *family;
830 Face *face;
831 const char *file;
832 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
833 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
835 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
836 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
838 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
840 if(face_name && strcmpiW(face_name, family->FamilyName))
841 continue;
842 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
844 if (!face->file)
845 continue;
846 file = strrchr(face->file, '/');
847 if(!file)
848 file = face->file;
849 else
850 file++;
851 if(!strcasecmp(file, file_nameA))
853 HeapFree(GetProcessHeap(), 0, file_nameA);
854 return face;
858 HeapFree(GetProcessHeap(), 0, file_nameA);
859 return NULL;
862 static Family *find_family_from_name(const WCHAR *name)
864 Family *family;
866 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
868 if(!strcmpiW(family->FamilyName, name))
869 return family;
872 return NULL;
875 static void DumpSubstList(void)
877 FontSubst *psub;
879 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
881 if(psub->from.charset != -1 || psub->to.charset != -1)
882 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
883 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
884 else
885 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
886 debugstr_w(psub->to.name));
888 return;
891 static LPWSTR strdupW(LPCWSTR p)
893 LPWSTR ret;
894 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
895 ret = HeapAlloc(GetProcessHeap(), 0, len);
896 memcpy(ret, p, len);
897 return ret;
900 static LPSTR strdupA(LPCSTR p)
902 LPSTR ret;
903 DWORD len = (strlen(p) + 1);
904 ret = HeapAlloc(GetProcessHeap(), 0, len);
905 memcpy(ret, p, len);
906 return ret;
909 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
910 INT from_charset)
912 FontSubst *element;
914 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
916 if(!strcmpiW(element->from.name, from_name) &&
917 (element->from.charset == from_charset ||
918 element->from.charset == -1))
919 return element;
922 return NULL;
925 #define ADD_FONT_SUBST_FORCE 1
927 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
929 FontSubst *from_exist, *to_exist;
931 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
933 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
935 list_remove(&from_exist->entry);
936 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
937 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
938 HeapFree(GetProcessHeap(), 0, from_exist);
939 from_exist = NULL;
942 if(!from_exist)
944 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
946 if(to_exist)
948 HeapFree(GetProcessHeap(), 0, subst->to.name);
949 subst->to.name = strdupW(to_exist->to.name);
952 list_add_tail(subst_list, &subst->entry);
954 return TRUE;
957 HeapFree(GetProcessHeap(), 0, subst->from.name);
958 HeapFree(GetProcessHeap(), 0, subst->to.name);
959 HeapFree(GetProcessHeap(), 0, subst);
960 return FALSE;
963 static void split_subst_info(NameCs *nc, LPSTR str)
965 CHAR *p = strrchr(str, ',');
966 DWORD len;
968 nc->charset = -1;
969 if(p && *(p+1)) {
970 nc->charset = strtol(p+1, NULL, 10);
971 *p = '\0';
973 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
974 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
975 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
978 static void LoadSubstList(void)
980 FontSubst *psub;
981 HKEY hkey;
982 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
983 LPSTR value;
984 LPVOID data;
986 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
987 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
988 &hkey) == ERROR_SUCCESS) {
990 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
991 &valuelen, &datalen, NULL, NULL);
993 valuelen++; /* returned value doesn't include room for '\0' */
994 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
995 data = HeapAlloc(GetProcessHeap(), 0, datalen);
997 dlen = datalen;
998 vlen = valuelen;
999 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1000 &dlen) == ERROR_SUCCESS) {
1001 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1003 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1004 split_subst_info(&psub->from, value);
1005 split_subst_info(&psub->to, data);
1007 /* Win 2000 doesn't allow mapping between different charsets
1008 or mapping of DEFAULT_CHARSET */
1009 if((psub->to.charset != psub->from.charset) ||
1010 psub->to.charset == DEFAULT_CHARSET) {
1011 HeapFree(GetProcessHeap(), 0, psub->to.name);
1012 HeapFree(GetProcessHeap(), 0, psub->from.name);
1013 HeapFree(GetProcessHeap(), 0, psub);
1014 } else {
1015 add_font_subst(&font_subst_list, psub, 0);
1017 /* reset dlen and vlen */
1018 dlen = datalen;
1019 vlen = valuelen;
1021 HeapFree(GetProcessHeap(), 0, data);
1022 HeapFree(GetProcessHeap(), 0, value);
1023 RegCloseKey(hkey);
1027 static WCHAR *get_familyname(FT_Face ft_face)
1029 WCHAR *family = NULL;
1030 FT_SfntName name;
1031 FT_UInt num_names, name_index, i;
1033 if(FT_IS_SFNT(ft_face))
1035 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1037 for(name_index = 0; name_index < num_names; name_index++)
1039 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1041 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1042 (name.language_id == GetUserDefaultLCID()) &&
1043 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1044 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1046 /* String is not nul terminated and string_len is a byte length. */
1047 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1048 for(i = 0; i < name.string_len / 2; i++)
1050 WORD *tmp = (WORD *)&name.string[i * 2];
1051 family[i] = GET_BE_WORD(*tmp);
1053 family[i] = 0;
1055 TRACE("Got localised name %s\n", debugstr_w(family));
1056 return family;
1062 return NULL;
1066 /*****************************************************************
1067 * load_sfnt_table
1069 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1070 * of FreeType that don't export this function.
1073 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1076 FT_Error err;
1078 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1079 if(pFT_Load_Sfnt_Table)
1081 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1083 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1084 else /* Do it the hard way */
1086 TT_Face tt_face = (TT_Face) ft_face;
1087 SFNT_Interface *sfnt;
1088 if (FT_Version.major==2 && FT_Version.minor==0)
1090 /* 2.0.x */
1091 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1093 else
1095 /* A field was added in the middle of the structure in 2.1.x */
1096 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1098 err = sfnt->load_any(tt_face, table, offset, buf, len);
1100 #else
1101 else
1103 static int msg;
1104 if(!msg)
1106 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1107 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1108 "Please upgrade your freetype library.\n");
1109 msg++;
1111 err = FT_Err_Unimplemented_Feature;
1113 #endif
1114 return err;
1117 static inline int TestStyles(DWORD flags, DWORD styles)
1119 return (flags & styles) == styles;
1122 static int StyleOrdering(Face *face)
1124 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1125 return 3;
1126 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1127 return 2;
1128 if (TestStyles(face->ntmFlags, NTM_BOLD))
1129 return 1;
1130 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1131 return 0;
1133 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1134 debugstr_w(face->family->FamilyName),
1135 debugstr_w(face->StyleName),
1136 face->ntmFlags);
1138 return 9999;
1141 /* Add a style of face to a font family using an ordering of the list such
1142 that regular fonts come before bold and italic, and single styles come
1143 before compound styles. */
1144 static void AddFaceToFamily(Face *face, Family *family)
1146 struct list *entry;
1148 LIST_FOR_EACH( entry, &family->faces )
1150 Face *ent = LIST_ENTRY(entry, Face, entry);
1151 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1153 list_add_before( entry, &face->entry );
1156 #define ADDFONT_EXTERNAL_FONT 0x01
1157 #define ADDFONT_FORCE_BITMAP 0x02
1158 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1160 FT_Face ft_face;
1161 TT_OS2 *pOS2;
1162 TT_Header *pHeader = NULL;
1163 WCHAR *english_family, *localised_family, *StyleW;
1164 DWORD len;
1165 Family *family;
1166 Face *face;
1167 struct list *family_elem_ptr, *face_elem_ptr;
1168 FT_Error err;
1169 FT_Long face_index = 0, num_faces;
1170 #ifdef HAVE_FREETYPE_FTWINFNT_H
1171 FT_WinFNT_HeaderRec winfnt_header;
1172 #endif
1173 int i, bitmap_num, internal_leading;
1174 FONTSIGNATURE fs;
1176 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1177 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1179 #ifdef HAVE_CARBON_CARBON_H
1180 if(file && !fake_family)
1182 char **mac_list = expand_mac_font(file);
1183 if(mac_list)
1185 BOOL had_one = FALSE;
1186 char **cursor;
1187 for(cursor = mac_list; *cursor; cursor++)
1189 had_one = TRUE;
1190 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1191 HeapFree(GetProcessHeap(), 0, *cursor);
1193 HeapFree(GetProcessHeap(), 0, mac_list);
1194 if(had_one)
1195 return 1;
1198 #endif /* HAVE_CARBON_CARBON_H */
1200 do {
1201 char *family_name = fake_family;
1203 if (file)
1205 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1206 err = pFT_New_Face(library, file, face_index, &ft_face);
1207 } else
1209 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1210 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1213 if(err != 0) {
1214 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1215 return 0;
1218 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*/
1219 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1220 pFT_Done_Face(ft_face);
1221 return 0;
1224 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1225 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1226 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1227 pFT_Done_Face(ft_face);
1228 return 0;
1231 if(FT_IS_SFNT(ft_face))
1233 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1234 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1235 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1237 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1238 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1239 pFT_Done_Face(ft_face);
1240 return 0;
1243 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1244 we don't want to load these. */
1245 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1247 FT_ULong len = 0;
1249 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1251 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1252 pFT_Done_Face(ft_face);
1253 return 0;
1258 if(!ft_face->family_name || !ft_face->style_name) {
1259 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1260 pFT_Done_Face(ft_face);
1261 return 0;
1264 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1266 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1267 pFT_Done_Face(ft_face);
1268 return 0;
1271 if (target_family)
1273 localised_family = get_familyname(ft_face);
1274 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1276 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1277 HeapFree(GetProcessHeap(), 0, localised_family);
1278 num_faces = ft_face->num_faces;
1279 pFT_Done_Face(ft_face);
1280 continue;
1282 HeapFree(GetProcessHeap(), 0, localised_family);
1285 if(!family_name)
1286 family_name = ft_face->family_name;
1288 bitmap_num = 0;
1289 do {
1290 My_FT_Bitmap_Size *size = NULL;
1291 FT_ULong tmp_size;
1293 if(!FT_IS_SCALABLE(ft_face))
1294 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1296 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1297 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1298 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1300 localised_family = NULL;
1301 if(!fake_family) {
1302 localised_family = get_familyname(ft_face);
1303 if(localised_family && !strcmpW(localised_family, english_family)) {
1304 HeapFree(GetProcessHeap(), 0, localised_family);
1305 localised_family = NULL;
1309 family = NULL;
1310 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1311 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1312 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1313 break;
1314 family = NULL;
1316 if(!family) {
1317 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1318 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1319 list_init(&family->faces);
1320 list_add_tail(&font_list, &family->entry);
1322 if(localised_family) {
1323 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1324 subst->from.name = strdupW(english_family);
1325 subst->from.charset = -1;
1326 subst->to.name = strdupW(localised_family);
1327 subst->to.charset = -1;
1328 add_font_subst(&font_subst_list, subst, 0);
1331 HeapFree(GetProcessHeap(), 0, localised_family);
1332 HeapFree(GetProcessHeap(), 0, english_family);
1334 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1335 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1336 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1338 internal_leading = 0;
1339 memset(&fs, 0, sizeof(fs));
1341 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1342 if(pOS2) {
1343 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1344 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1345 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1346 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1347 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1348 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1349 if(pOS2->version == 0) {
1350 FT_UInt dummy;
1352 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1353 fs.fsCsb[0] |= FS_LATIN1;
1354 else
1355 fs.fsCsb[0] |= FS_SYMBOL;
1358 #ifdef HAVE_FREETYPE_FTWINFNT_H
1359 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1360 CHARSETINFO csi;
1361 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1362 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1363 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1364 fs = csi.fs;
1365 internal_leading = winfnt_header.internal_leading;
1367 #endif
1369 face_elem_ptr = list_head(&family->faces);
1370 while(face_elem_ptr) {
1371 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1372 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1373 if(!strcmpW(face->StyleName, StyleW) &&
1374 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1375 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1376 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1377 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1379 if(fake_family) {
1380 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1381 HeapFree(GetProcessHeap(), 0, StyleW);
1382 pFT_Done_Face(ft_face);
1383 return 1;
1385 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1386 TRACE("Original font is newer so skipping this one\n");
1387 HeapFree(GetProcessHeap(), 0, StyleW);
1388 pFT_Done_Face(ft_face);
1389 return 1;
1390 } else {
1391 TRACE("Replacing original with this one\n");
1392 list_remove(&face->entry);
1393 HeapFree(GetProcessHeap(), 0, face->file);
1394 HeapFree(GetProcessHeap(), 0, face->StyleName);
1395 HeapFree(GetProcessHeap(), 0, face);
1396 break;
1400 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1401 face->cached_enum_data = NULL;
1402 face->StyleName = StyleW;
1403 if (file)
1405 face->file = strdupA(file);
1406 face->font_data_ptr = NULL;
1407 face->font_data_size = 0;
1409 else
1411 face->file = NULL;
1412 face->font_data_ptr = font_data_ptr;
1413 face->font_data_size = font_data_size;
1415 face->face_index = face_index;
1416 face->ntmFlags = 0;
1417 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1418 face->ntmFlags |= NTM_ITALIC;
1419 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1420 face->ntmFlags |= NTM_BOLD;
1421 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1422 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1423 face->family = family;
1424 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1425 face->fs = fs;
1426 memset(&face->fs_links, 0, sizeof(face->fs_links));
1428 if(FT_IS_SCALABLE(ft_face)) {
1429 memset(&face->size, 0, sizeof(face->size));
1430 face->scalable = TRUE;
1431 } else {
1432 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1433 size->height, size->width, size->size >> 6,
1434 size->x_ppem >> 6, size->y_ppem >> 6);
1435 face->size.height = size->height;
1436 face->size.width = size->width;
1437 face->size.size = size->size;
1438 face->size.x_ppem = size->x_ppem;
1439 face->size.y_ppem = size->y_ppem;
1440 face->size.internal_leading = internal_leading;
1441 face->scalable = FALSE;
1444 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1445 tmp_size = 0;
1446 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1448 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1449 face->ntmFlags |= NTM_PS_OPENTYPE;
1452 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1453 face->fs.fsCsb[0], face->fs.fsCsb[1],
1454 face->fs.fsUsb[0], face->fs.fsUsb[1],
1455 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1458 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1459 for(i = 0; i < ft_face->num_charmaps; i++) {
1460 switch(ft_face->charmaps[i]->encoding) {
1461 case FT_ENCODING_UNICODE:
1462 case FT_ENCODING_APPLE_ROMAN:
1463 face->fs.fsCsb[0] |= FS_LATIN1;
1464 break;
1465 case FT_ENCODING_MS_SYMBOL:
1466 face->fs.fsCsb[0] |= FS_SYMBOL;
1467 break;
1468 default:
1469 break;
1474 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1475 have_installed_roman_font = TRUE;
1477 AddFaceToFamily(face, family);
1479 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1481 num_faces = ft_face->num_faces;
1482 pFT_Done_Face(ft_face);
1483 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1484 debugstr_w(StyleW));
1485 } while(num_faces > ++face_index);
1486 return num_faces;
1489 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1491 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1494 static void DumpFontList(void)
1496 Family *family;
1497 Face *face;
1498 struct list *family_elem_ptr, *face_elem_ptr;
1500 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1501 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1502 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1503 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1504 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1505 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1506 if(!face->scalable)
1507 TRACE(" %d", face->size.height);
1508 TRACE("\n");
1511 return;
1514 /***********************************************************
1515 * The replacement list is a way to map an entire font
1516 * family onto another family. For example adding
1518 * [HKCU\Software\Wine\Fonts\Replacements]
1519 * "Wingdings"="Winedings"
1521 * would enumerate the Winedings font both as Winedings and
1522 * Wingdings. However if a real Wingdings font is present the
1523 * replacement does not take place.
1526 static void LoadReplaceList(void)
1528 HKEY hkey;
1529 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1530 LPWSTR value;
1531 LPVOID data;
1532 Family *family;
1533 Face *face;
1534 struct list *family_elem_ptr, *face_elem_ptr;
1535 CHAR familyA[400];
1537 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1538 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1540 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1541 &valuelen, &datalen, NULL, NULL);
1543 valuelen++; /* returned value doesn't include room for '\0' */
1544 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1545 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1547 dlen = datalen;
1548 vlen = valuelen;
1549 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1550 &dlen) == ERROR_SUCCESS) {
1551 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1552 /* "NewName"="Oldname" */
1553 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1555 /* Find the old family and hence all of the font files
1556 in that family */
1557 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1558 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1559 if(!strcmpiW(family->FamilyName, data)) {
1560 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1561 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1562 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1563 debugstr_w(face->StyleName), familyA);
1564 /* Now add a new entry with the new family name */
1565 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1567 break;
1570 /* reset dlen and vlen */
1571 dlen = datalen;
1572 vlen = valuelen;
1574 HeapFree(GetProcessHeap(), 0, data);
1575 HeapFree(GetProcessHeap(), 0, value);
1576 RegCloseKey(hkey);
1580 /*************************************************************
1581 * init_system_links
1583 static BOOL init_system_links(void)
1585 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1586 'W','i','n','d','o','w','s',' ','N','T','\\',
1587 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1588 'S','y','s','t','e','m','L','i','n','k',0};
1589 HKEY hkey;
1590 BOOL ret = FALSE;
1591 DWORD type, max_val, max_data, val_len, data_len, index;
1592 WCHAR *value, *data;
1593 WCHAR *entry, *next;
1594 SYSTEM_LINKS *font_link, *system_font_link;
1595 CHILD_FONT *child_font;
1596 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1597 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1598 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1599 FONTSIGNATURE fs;
1600 Family *family;
1601 Face *face;
1602 FontSubst *psub;
1604 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1606 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1607 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1608 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1609 val_len = max_val + 1;
1610 data_len = max_data;
1611 index = 0;
1612 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1614 TRACE("%s:\n", debugstr_w(value));
1616 memset(&fs, 0, sizeof(fs));
1617 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1618 psub = get_font_subst(&font_subst_list, value, -1);
1619 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1620 list_init(&font_link->links);
1621 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1623 WCHAR *face_name;
1624 CHILD_FONT *child_font;
1626 TRACE("\t%s\n", debugstr_w(entry));
1628 next = entry + strlenW(entry) + 1;
1630 face_name = strchrW(entry, ',');
1631 if(face_name)
1633 *face_name++ = 0;
1634 while(isspaceW(*face_name))
1635 face_name++;
1637 psub = get_font_subst(&font_subst_list, face_name, -1);
1638 if(psub)
1639 face_name = psub->to.name;
1641 face = find_face_from_filename(entry, face_name);
1642 if(!face)
1644 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1645 continue;
1648 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1649 child_font->face = face;
1650 child_font->font = NULL;
1651 fs.fsCsb[0] |= face->fs.fsCsb[0];
1652 fs.fsCsb[1] |= face->fs.fsCsb[1];
1653 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1654 list_add_tail(&font_link->links, &child_font->entry);
1656 family = find_family_from_name(font_link->font_name);
1657 if(family)
1659 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1661 face->fs_links = fs;
1664 list_add_tail(&system_links, &font_link->entry);
1665 val_len = max_val + 1;
1666 data_len = max_data;
1669 HeapFree(GetProcessHeap(), 0, value);
1670 HeapFree(GetProcessHeap(), 0, data);
1671 RegCloseKey(hkey);
1674 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1675 that Tahoma has */
1677 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1678 system_font_link->font_name = strdupW(System);
1679 list_init(&system_font_link->links);
1681 face = find_face_from_filename(tahoma_ttf, Tahoma);
1682 if(face)
1684 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1685 child_font->face = face;
1686 child_font->font = NULL;
1687 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1688 list_add_tail(&system_font_link->links, &child_font->entry);
1690 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1692 if(!strcmpiW(font_link->font_name, Tahoma))
1694 CHILD_FONT *font_link_entry;
1695 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1697 CHILD_FONT *new_child;
1698 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1699 new_child->face = font_link_entry->face;
1700 new_child->font = NULL;
1701 list_add_tail(&system_font_link->links, &new_child->entry);
1703 break;
1706 list_add_tail(&system_links, &system_font_link->entry);
1707 return ret;
1710 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1712 DIR *dir;
1713 struct dirent *dent;
1714 char path[MAX_PATH];
1716 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1718 dir = opendir(dirname);
1719 if(!dir) {
1720 WARN("Can't open directory %s\n", debugstr_a(dirname));
1721 return FALSE;
1723 while((dent = readdir(dir)) != NULL) {
1724 struct stat statbuf;
1726 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1727 continue;
1729 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1731 sprintf(path, "%s/%s", dirname, dent->d_name);
1733 if(stat(path, &statbuf) == -1)
1735 WARN("Can't stat %s\n", debugstr_a(path));
1736 continue;
1738 if(S_ISDIR(statbuf.st_mode))
1739 ReadFontDir(path, external_fonts);
1740 else
1741 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1743 closedir(dir);
1744 return TRUE;
1747 static void load_fontconfig_fonts(void)
1749 #ifdef SONAME_LIBFONTCONFIG
1750 void *fc_handle = NULL;
1751 FcConfig *config;
1752 FcPattern *pat;
1753 FcObjectSet *os;
1754 FcFontSet *fontset;
1755 int i, len;
1756 char *file;
1757 const char *ext;
1759 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1760 if(!fc_handle) {
1761 TRACE("Wine cannot find the fontconfig library (%s).\n",
1762 SONAME_LIBFONTCONFIG);
1763 return;
1765 #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;}
1766 LOAD_FUNCPTR(FcConfigGetCurrent);
1767 LOAD_FUNCPTR(FcFontList);
1768 LOAD_FUNCPTR(FcFontSetDestroy);
1769 LOAD_FUNCPTR(FcInit);
1770 LOAD_FUNCPTR(FcObjectSetAdd);
1771 LOAD_FUNCPTR(FcObjectSetCreate);
1772 LOAD_FUNCPTR(FcObjectSetDestroy);
1773 LOAD_FUNCPTR(FcPatternCreate);
1774 LOAD_FUNCPTR(FcPatternDestroy);
1775 LOAD_FUNCPTR(FcPatternGetBool);
1776 LOAD_FUNCPTR(FcPatternGetString);
1777 #undef LOAD_FUNCPTR
1779 if(!pFcInit()) return;
1781 config = pFcConfigGetCurrent();
1782 pat = pFcPatternCreate();
1783 os = pFcObjectSetCreate();
1784 pFcObjectSetAdd(os, FC_FILE);
1785 pFcObjectSetAdd(os, FC_SCALABLE);
1786 fontset = pFcFontList(config, pat, os);
1787 if(!fontset) return;
1788 for(i = 0; i < fontset->nfont; i++) {
1789 FcBool scalable;
1791 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1792 continue;
1793 TRACE("fontconfig: %s\n", file);
1795 /* We're just interested in OT/TT fonts for now, so this hack just
1796 picks up the scalable fonts without extensions .pf[ab] to save time
1797 loading every other font */
1799 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1801 TRACE("not scalable\n");
1802 continue;
1805 len = strlen( file );
1806 if(len < 4) continue;
1807 ext = &file[ len - 3 ];
1808 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1809 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1811 pFcFontSetDestroy(fontset);
1812 pFcObjectSetDestroy(os);
1813 pFcPatternDestroy(pat);
1814 sym_not_found:
1815 #endif
1816 return;
1819 static BOOL load_font_from_data_dir(LPCWSTR file)
1821 BOOL ret = FALSE;
1822 const char *data_dir = wine_get_data_dir();
1824 if (!data_dir) data_dir = wine_get_build_dir();
1826 if (data_dir)
1828 INT len;
1829 char *unix_name;
1831 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1833 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1835 strcpy(unix_name, data_dir);
1836 strcat(unix_name, "/fonts/");
1838 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1840 EnterCriticalSection( &freetype_cs );
1841 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1842 LeaveCriticalSection( &freetype_cs );
1843 HeapFree(GetProcessHeap(), 0, unix_name);
1845 return ret;
1848 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1850 static const WCHAR slashW[] = {'\\','\0'};
1851 BOOL ret = FALSE;
1852 WCHAR windowsdir[MAX_PATH];
1853 char *unixname;
1855 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1856 strcatW(windowsdir, fontsW);
1857 strcatW(windowsdir, slashW);
1858 strcatW(windowsdir, file);
1859 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1860 EnterCriticalSection( &freetype_cs );
1861 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1862 LeaveCriticalSection( &freetype_cs );
1863 HeapFree(GetProcessHeap(), 0, unixname);
1865 return ret;
1868 static void load_system_fonts(void)
1870 HKEY hkey;
1871 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1872 const WCHAR * const *value;
1873 DWORD dlen, type;
1874 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1875 char *unixname;
1877 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1878 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1879 strcatW(windowsdir, fontsW);
1880 for(value = SystemFontValues; *value; value++) {
1881 dlen = sizeof(data);
1882 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1883 type == REG_SZ) {
1884 BOOL added = FALSE;
1886 sprintfW(pathW, fmtW, windowsdir, data);
1887 if((unixname = wine_get_unix_file_name(pathW))) {
1888 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1889 HeapFree(GetProcessHeap(), 0, unixname);
1891 if (!added)
1892 load_font_from_data_dir(data);
1895 RegCloseKey(hkey);
1899 /*************************************************************
1901 * This adds registry entries for any externally loaded fonts
1902 * (fonts from fontconfig or FontDirs). It also deletes entries
1903 * of no longer existing fonts.
1906 static void update_reg_entries(void)
1908 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1909 LPWSTR valueW;
1910 DWORD len, len_fam;
1911 Family *family;
1912 Face *face;
1913 struct list *family_elem_ptr, *face_elem_ptr;
1914 WCHAR *file;
1915 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1916 static const WCHAR spaceW[] = {' ', '\0'};
1917 char *path;
1919 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1920 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1921 ERR("Can't create Windows font reg key\n");
1922 goto end;
1925 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1926 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1927 ERR("Can't create Windows font reg key\n");
1928 goto end;
1931 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1932 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1933 ERR("Can't create external font reg key\n");
1934 goto end;
1937 /* enumerate the fonts and add external ones to the two keys */
1939 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1940 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1941 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1942 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1943 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1944 if(!face->external) continue;
1945 len = len_fam;
1946 if (!(face->ntmFlags & NTM_REGULAR))
1947 len = len_fam + strlenW(face->StyleName) + 1;
1948 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1949 strcpyW(valueW, family->FamilyName);
1950 if(len != len_fam) {
1951 strcatW(valueW, spaceW);
1952 strcatW(valueW, face->StyleName);
1954 strcatW(valueW, TrueType);
1956 file = wine_get_dos_file_name(face->file);
1957 if(file)
1958 len = strlenW(file) + 1;
1959 else
1961 if((path = strrchr(face->file, '/')) == NULL)
1962 path = face->file;
1963 else
1964 path++;
1965 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1967 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1968 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1970 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1971 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1972 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1974 HeapFree(GetProcessHeap(), 0, file);
1975 HeapFree(GetProcessHeap(), 0, valueW);
1978 end:
1979 if(external_key) RegCloseKey(external_key);
1980 if(win9x_key) RegCloseKey(win9x_key);
1981 if(winnt_key) RegCloseKey(winnt_key);
1982 return;
1985 static void delete_external_font_keys(void)
1987 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1988 DWORD dlen, vlen, datalen, valuelen, i, type;
1989 LPWSTR valueW;
1990 LPVOID data;
1992 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1993 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1994 ERR("Can't create Windows font reg key\n");
1995 goto end;
1998 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1999 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2000 ERR("Can't create Windows font reg key\n");
2001 goto end;
2004 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2005 ERR("Can't create external font reg key\n");
2006 goto end;
2009 /* Delete all external fonts added last time */
2011 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2012 &valuelen, &datalen, NULL, NULL);
2013 valuelen++; /* returned value doesn't include room for '\0' */
2014 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2015 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2017 dlen = datalen * sizeof(WCHAR);
2018 vlen = valuelen;
2019 i = 0;
2020 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2021 &dlen) == ERROR_SUCCESS) {
2023 RegDeleteValueW(winnt_key, valueW);
2024 RegDeleteValueW(win9x_key, valueW);
2025 /* reset dlen and vlen */
2026 dlen = datalen;
2027 vlen = valuelen;
2029 HeapFree(GetProcessHeap(), 0, data);
2030 HeapFree(GetProcessHeap(), 0, valueW);
2032 /* Delete the old external fonts key */
2033 RegCloseKey(external_key);
2034 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2036 end:
2037 if(win9x_key) RegCloseKey(win9x_key);
2038 if(winnt_key) RegCloseKey(winnt_key);
2041 /*************************************************************
2042 * WineEngAddFontResourceEx
2045 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2047 INT ret = 0;
2048 if (ft_handle) /* do it only if we have freetype up and running */
2050 char *unixname;
2052 if(flags)
2053 FIXME("Ignoring flags %x\n", flags);
2055 if((unixname = wine_get_unix_file_name(file)))
2057 EnterCriticalSection( &freetype_cs );
2058 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2059 LeaveCriticalSection( &freetype_cs );
2060 HeapFree(GetProcessHeap(), 0, unixname);
2062 if (!ret && !strchrW(file, '\\')) {
2063 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2064 ret = load_font_from_winfonts_dir(file);
2065 if (!ret) {
2066 /* Try in datadir/fonts (or builddir/fonts),
2067 * needed for Magic the Gathering Online
2069 ret = load_font_from_data_dir(file);
2073 return ret;
2076 /*************************************************************
2077 * WineEngAddFontMemResourceEx
2080 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2082 if (ft_handle) /* do it only if we have freetype up and running */
2084 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2086 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2087 memcpy(pFontCopy, pbFont, cbFont);
2089 EnterCriticalSection( &freetype_cs );
2090 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2091 LeaveCriticalSection( &freetype_cs );
2093 if (*pcFonts == 0)
2095 TRACE("AddFontToList failed\n");
2096 HeapFree(GetProcessHeap(), 0, pFontCopy);
2097 return NULL;
2099 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2100 * For now return something unique but quite random
2102 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2103 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2106 *pcFonts = 0;
2107 return 0;
2110 /*************************************************************
2111 * WineEngRemoveFontResourceEx
2114 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2116 FIXME(":stub\n");
2117 return TRUE;
2120 static const struct nls_update_font_list
2122 UINT ansi_cp, oem_cp;
2123 const char *oem, *fixed, *system;
2124 const char *courier, *serif, *small, *sserif;
2125 /* these are for font substitute */
2126 const char *shelldlg, *tmsrmn;
2127 } nls_update_font_list[] =
2129 /* Latin 1 (United States) */
2130 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2131 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2132 "Tahoma","Times New Roman",
2134 /* Latin 1 (Multilingual) */
2135 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2136 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2137 "Tahoma","Times New Roman", /* FIXME unverified */
2139 /* Eastern Europe */
2140 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2141 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2142 "Tahoma","Times New Roman", /* FIXME unverified */
2144 /* Cyrillic */
2145 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2146 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2147 "Tahoma","Times New Roman", /* FIXME unverified */
2149 /* Greek */
2150 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2151 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2152 "Tahoma","Times New Roman", /* FIXME unverified */
2154 /* Turkish */
2155 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2156 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2157 "Tahoma","Times New Roman", /* FIXME unverified */
2159 /* Hebrew */
2160 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2161 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2162 "Tahoma","Times New Roman", /* FIXME unverified */
2164 /* Arabic */
2165 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2166 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2167 "Tahoma","Times New Roman", /* FIXME unverified */
2169 /* Baltic */
2170 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2171 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2172 "Tahoma","Times New Roman", /* FIXME unverified */
2174 /* Vietnamese */
2175 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2176 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2177 "Tahoma","Times New Roman", /* FIXME unverified */
2179 /* Thai */
2180 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2181 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2182 "Tahoma","Times New Roman", /* FIXME unverified */
2184 /* Japanese */
2185 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2186 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2187 "MS UI Gothic","MS Serif",
2189 /* Chinese Simplified */
2190 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2191 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2192 "Tahoma", "Times New Roman", /* FIXME unverified */
2194 /* Korean */
2195 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2196 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2197 "Gulim", "Batang",
2199 /* Chinese Traditional */
2200 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "PMingLiU", "MingLiU",
2206 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2208 return ( ansi_cp == 932 /* CP932 for Japanese */
2209 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2210 || ansi_cp == 949 /* CP949 for Korean */
2211 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2214 static inline HKEY create_fonts_NT_registry_key(void)
2216 HKEY hkey = 0;
2218 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2219 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2220 return hkey;
2223 static inline HKEY create_fonts_9x_registry_key(void)
2225 HKEY hkey = 0;
2227 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2228 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2229 return hkey;
2232 static inline HKEY create_config_fonts_registry_key(void)
2234 HKEY hkey = 0;
2236 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2237 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2238 return hkey;
2241 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2243 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2244 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2245 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2246 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2249 static void update_font_info(void)
2251 char buf[40], cpbuf[40];
2252 DWORD len, type;
2253 HKEY hkey = 0;
2254 UINT i, ansi_cp = 0, oem_cp = 0;
2256 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2257 return;
2259 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2260 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2261 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2262 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2263 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2265 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2266 if (is_dbcs_ansi_cp(ansi_cp))
2267 use_default_fallback = TRUE;
2269 len = sizeof(buf);
2270 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2272 if (!strcmp( buf, cpbuf )) /* already set correctly */
2274 RegCloseKey(hkey);
2275 return;
2277 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2279 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2281 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2282 RegCloseKey(hkey);
2284 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2286 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2287 nls_update_font_list[i].oem_cp == oem_cp)
2289 HKEY hkey;
2291 hkey = create_config_fonts_registry_key();
2292 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2293 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2294 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2295 RegCloseKey(hkey);
2297 hkey = create_fonts_NT_registry_key();
2298 add_font_list(hkey, &nls_update_font_list[i]);
2299 RegCloseKey(hkey);
2301 hkey = create_fonts_9x_registry_key();
2302 add_font_list(hkey, &nls_update_font_list[i]);
2303 RegCloseKey(hkey);
2305 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2307 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2308 strlen(nls_update_font_list[i].shelldlg)+1);
2309 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2310 strlen(nls_update_font_list[i].tmsrmn)+1);
2311 RegCloseKey(hkey);
2313 return;
2316 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2320 static BOOL init_freetype(void)
2322 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2323 if(!ft_handle) {
2324 WINE_MESSAGE(
2325 "Wine cannot find the FreeType font library. To enable Wine to\n"
2326 "use TrueType fonts please install a version of FreeType greater than\n"
2327 "or equal to 2.0.5.\n"
2328 "http://www.freetype.org\n");
2329 return FALSE;
2332 #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;}
2334 LOAD_FUNCPTR(FT_Vector_Unit)
2335 LOAD_FUNCPTR(FT_Done_Face)
2336 LOAD_FUNCPTR(FT_Get_Char_Index)
2337 LOAD_FUNCPTR(FT_Get_Module)
2338 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2339 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2340 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2341 LOAD_FUNCPTR(FT_Init_FreeType)
2342 LOAD_FUNCPTR(FT_Load_Glyph)
2343 LOAD_FUNCPTR(FT_Matrix_Multiply)
2344 LOAD_FUNCPTR(FT_MulFix)
2345 LOAD_FUNCPTR(FT_New_Face)
2346 LOAD_FUNCPTR(FT_New_Memory_Face)
2347 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2348 LOAD_FUNCPTR(FT_Outline_Transform)
2349 LOAD_FUNCPTR(FT_Outline_Translate)
2350 LOAD_FUNCPTR(FT_Select_Charmap)
2351 LOAD_FUNCPTR(FT_Set_Charmap)
2352 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2353 LOAD_FUNCPTR(FT_Vector_Transform)
2355 #undef LOAD_FUNCPTR
2356 /* Don't warn if these ones are missing */
2357 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2358 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2359 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2360 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2361 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2362 #ifdef HAVE_FREETYPE_FTWINFNT_H
2363 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2364 #endif
2365 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2366 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2367 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2368 <= 2.0.3 has FT_Sqrt64 */
2369 goto sym_not_found;
2372 if(pFT_Init_FreeType(&library) != 0) {
2373 ERR("Can't init FreeType library\n");
2374 wine_dlclose(ft_handle, NULL, 0);
2375 ft_handle = NULL;
2376 return FALSE;
2378 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2379 if (pFT_Library_Version)
2380 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2382 if (FT_Version.major<=0)
2384 FT_Version.major=2;
2385 FT_Version.minor=0;
2386 FT_Version.patch=5;
2388 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2389 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2390 ((FT_Version.minor << 8) & 0x00ff00) |
2391 ((FT_Version.patch ) & 0x0000ff);
2393 return TRUE;
2395 sym_not_found:
2396 WINE_MESSAGE(
2397 "Wine cannot find certain functions that it needs inside the FreeType\n"
2398 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2399 "FreeType to at least version 2.0.5.\n"
2400 "http://www.freetype.org\n");
2401 wine_dlclose(ft_handle, NULL, 0);
2402 ft_handle = NULL;
2403 return FALSE;
2406 /*************************************************************
2407 * WineEngInit
2409 * Initialize FreeType library and create a list of available faces
2411 BOOL WineEngInit(void)
2413 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2414 static const WCHAR pathW[] = {'P','a','t','h',0};
2415 HKEY hkey;
2416 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2417 LPVOID data;
2418 WCHAR windowsdir[MAX_PATH];
2419 char *unixname;
2420 HANDLE font_mutex;
2421 const char *data_dir;
2423 TRACE("\n");
2425 /* update locale dependent font info in registry */
2426 update_font_info();
2428 if(!init_freetype()) return FALSE;
2430 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2431 ERR("Failed to create font mutex\n");
2432 return FALSE;
2434 WaitForSingleObject(font_mutex, INFINITE);
2436 delete_external_font_keys();
2438 /* load the system bitmap fonts */
2439 load_system_fonts();
2441 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2442 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2443 strcatW(windowsdir, fontsW);
2444 if((unixname = wine_get_unix_file_name(windowsdir)))
2446 ReadFontDir(unixname, FALSE);
2447 HeapFree(GetProcessHeap(), 0, unixname);
2450 /* load the system truetype fonts */
2451 data_dir = wine_get_data_dir();
2452 if (!data_dir) data_dir = wine_get_build_dir();
2453 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2454 strcpy(unixname, data_dir);
2455 strcat(unixname, "/fonts/");
2456 ReadFontDir(unixname, TRUE);
2457 HeapFree(GetProcessHeap(), 0, unixname);
2460 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2461 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2462 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2463 will skip these. */
2464 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2465 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2466 &hkey) == ERROR_SUCCESS) {
2467 LPWSTR valueW;
2468 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2469 &valuelen, &datalen, NULL, NULL);
2471 valuelen++; /* returned value doesn't include room for '\0' */
2472 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2473 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2474 if (valueW && data)
2476 dlen = datalen * sizeof(WCHAR);
2477 vlen = valuelen;
2478 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2479 &dlen) == ERROR_SUCCESS) {
2480 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2482 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2484 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2485 HeapFree(GetProcessHeap(), 0, unixname);
2488 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2490 WCHAR pathW[MAX_PATH];
2491 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2492 BOOL added = FALSE;
2494 sprintfW(pathW, fmtW, windowsdir, data);
2495 if((unixname = wine_get_unix_file_name(pathW)))
2497 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2498 HeapFree(GetProcessHeap(), 0, unixname);
2500 if (!added)
2501 load_font_from_data_dir(data);
2503 /* reset dlen and vlen */
2504 dlen = datalen;
2505 vlen = valuelen;
2508 HeapFree(GetProcessHeap(), 0, data);
2509 HeapFree(GetProcessHeap(), 0, valueW);
2510 RegCloseKey(hkey);
2513 load_fontconfig_fonts();
2515 /* then look in any directories that we've specified in the config file */
2516 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2517 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2519 DWORD len;
2520 LPWSTR valueW;
2521 LPSTR valueA, ptr;
2523 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2525 len += sizeof(WCHAR);
2526 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2527 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2529 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2530 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2531 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2532 TRACE( "got font path %s\n", debugstr_a(valueA) );
2533 ptr = valueA;
2534 while (ptr)
2536 LPSTR next = strchr( ptr, ':' );
2537 if (next) *next++ = 0;
2538 ReadFontDir( ptr, TRUE );
2539 ptr = next;
2541 HeapFree( GetProcessHeap(), 0, valueA );
2543 HeapFree( GetProcessHeap(), 0, valueW );
2545 RegCloseKey(hkey);
2548 DumpFontList();
2549 LoadSubstList();
2550 DumpSubstList();
2551 LoadReplaceList();
2552 update_reg_entries();
2554 init_system_links();
2556 ReleaseMutex(font_mutex);
2557 return TRUE;
2561 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2563 TT_OS2 *pOS2;
2564 TT_HoriHeader *pHori;
2566 LONG ppem;
2568 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2569 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2571 if(height == 0) height = 16;
2573 /* Calc. height of EM square:
2575 * For +ve lfHeight we have
2576 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2577 * Re-arranging gives:
2578 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2580 * For -ve lfHeight we have
2581 * |lfHeight| = ppem
2582 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2583 * with il = winAscent + winDescent - units_per_em]
2587 if(height > 0) {
2588 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2589 ppem = ft_face->units_per_EM * height /
2590 (pHori->Ascender - pHori->Descender);
2591 else
2592 ppem = ft_face->units_per_EM * height /
2593 (pOS2->usWinAscent + pOS2->usWinDescent);
2595 else
2596 ppem = -height;
2598 return ppem;
2601 static struct font_mapping *map_font_file( const char *name )
2603 struct font_mapping *mapping;
2604 struct stat st;
2605 int fd;
2607 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2608 if (fstat( fd, &st ) == -1) goto error;
2610 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2612 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2614 mapping->refcount++;
2615 close( fd );
2616 return mapping;
2619 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2620 goto error;
2622 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2623 close( fd );
2625 if (mapping->data == MAP_FAILED)
2627 HeapFree( GetProcessHeap(), 0, mapping );
2628 return NULL;
2630 mapping->refcount = 1;
2631 mapping->dev = st.st_dev;
2632 mapping->ino = st.st_ino;
2633 mapping->size = st.st_size;
2634 list_add_tail( &mappings_list, &mapping->entry );
2635 return mapping;
2637 error:
2638 close( fd );
2639 return NULL;
2642 static void unmap_font_file( struct font_mapping *mapping )
2644 if (!--mapping->refcount)
2646 list_remove( &mapping->entry );
2647 munmap( mapping->data, mapping->size );
2648 HeapFree( GetProcessHeap(), 0, mapping );
2652 static LONG load_VDMX(GdiFont*, LONG);
2654 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2656 FT_Error err;
2657 FT_Face ft_face;
2658 void *data_ptr;
2659 DWORD data_size;
2661 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2663 if (face->file)
2665 if (!(font->mapping = map_font_file( face->file )))
2667 WARN("failed to map %s\n", debugstr_a(face->file));
2668 return 0;
2670 data_ptr = font->mapping->data;
2671 data_size = font->mapping->size;
2673 else
2675 data_ptr = face->font_data_ptr;
2676 data_size = face->font_data_size;
2679 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2680 if(err) {
2681 ERR("FT_New_Face rets %d\n", err);
2682 return 0;
2685 /* set it here, as load_VDMX needs it */
2686 font->ft_face = ft_face;
2688 if(FT_IS_SCALABLE(ft_face)) {
2689 /* load the VDMX table if we have one */
2690 font->ppem = load_VDMX(font, height);
2691 if(font->ppem == 0)
2692 font->ppem = calc_ppem_for_height(ft_face, height);
2694 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2695 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2696 } else {
2697 font->ppem = height;
2698 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2699 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2701 return ft_face;
2705 static int get_nearest_charset(Face *face, int *cp)
2707 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2708 a single face with the requested charset. The idea is to check if
2709 the selected font supports the current ANSI codepage, if it does
2710 return the corresponding charset, else return the first charset */
2712 CHARSETINFO csi;
2713 int acp = GetACP(), i;
2714 DWORD fs0;
2716 *cp = acp;
2717 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2718 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2719 return csi.ciCharset;
2721 for(i = 0; i < 32; i++) {
2722 fs0 = 1L << i;
2723 if(face->fs.fsCsb[0] & fs0) {
2724 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2725 *cp = csi.ciACP;
2726 return csi.ciCharset;
2728 else
2729 FIXME("TCI failing on %x\n", fs0);
2733 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2734 face->fs.fsCsb[0], face->file);
2735 *cp = acp;
2736 return DEFAULT_CHARSET;
2739 static GdiFont *alloc_font(void)
2741 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2742 ret->gmsize = 1;
2743 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2744 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2745 ret->potm = NULL;
2746 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2747 ret->total_kern_pairs = (DWORD)-1;
2748 ret->kern_pairs = NULL;
2749 list_init(&ret->hfontlist);
2750 list_init(&ret->child_fonts);
2751 return ret;
2754 static void free_font(GdiFont *font)
2756 struct list *cursor, *cursor2;
2757 int i;
2759 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2761 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2762 struct list *first_hfont;
2763 HFONTLIST *hfontlist;
2764 list_remove(cursor);
2765 if(child->font)
2767 first_hfont = list_head(&child->font->hfontlist);
2768 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2769 DeleteObject(hfontlist->hfont);
2770 HeapFree(GetProcessHeap(), 0, hfontlist);
2771 free_font(child->font);
2773 HeapFree(GetProcessHeap(), 0, child);
2776 if (font->ft_face) pFT_Done_Face(font->ft_face);
2777 if (font->mapping) unmap_font_file( font->mapping );
2778 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2779 HeapFree(GetProcessHeap(), 0, font->potm);
2780 HeapFree(GetProcessHeap(), 0, font->name);
2781 for (i = 0; i < font->gmsize; i++)
2782 HeapFree(GetProcessHeap(),0,font->gm[i]);
2783 HeapFree(GetProcessHeap(), 0, font->gm);
2784 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2785 HeapFree(GetProcessHeap(), 0, font);
2789 /*************************************************************
2790 * load_VDMX
2792 * load the vdmx entry for the specified height
2795 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2796 ( ( (FT_ULong)_x4 << 24 ) | \
2797 ( (FT_ULong)_x3 << 16 ) | \
2798 ( (FT_ULong)_x2 << 8 ) | \
2799 (FT_ULong)_x1 )
2801 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2803 typedef struct {
2804 BYTE bCharSet;
2805 BYTE xRatio;
2806 BYTE yStartRatio;
2807 BYTE yEndRatio;
2808 } Ratios;
2810 typedef struct {
2811 WORD recs;
2812 BYTE startsz;
2813 BYTE endsz;
2814 } VDMX_group;
2816 static LONG load_VDMX(GdiFont *font, LONG height)
2818 WORD hdr[3], tmp;
2819 VDMX_group group;
2820 BYTE devXRatio, devYRatio;
2821 USHORT numRecs, numRatios;
2822 DWORD result, offset = -1;
2823 LONG ppem = 0;
2824 int i;
2826 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2828 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2829 return ppem;
2831 /* FIXME: need the real device aspect ratio */
2832 devXRatio = 1;
2833 devYRatio = 1;
2835 numRecs = GET_BE_WORD(hdr[1]);
2836 numRatios = GET_BE_WORD(hdr[2]);
2838 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2839 for(i = 0; i < numRatios; i++) {
2840 Ratios ratio;
2842 offset = (3 * 2) + (i * sizeof(Ratios));
2843 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2844 offset = -1;
2846 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2848 if((ratio.xRatio == 0 &&
2849 ratio.yStartRatio == 0 &&
2850 ratio.yEndRatio == 0) ||
2851 (devXRatio == ratio.xRatio &&
2852 devYRatio >= ratio.yStartRatio &&
2853 devYRatio <= ratio.yEndRatio))
2855 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2856 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2857 offset = GET_BE_WORD(tmp);
2858 break;
2862 if(offset == -1) {
2863 FIXME("No suitable ratio found\n");
2864 return ppem;
2867 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2868 USHORT recs;
2869 BYTE startsz, endsz;
2870 WORD *vTable;
2872 recs = GET_BE_WORD(group.recs);
2873 startsz = group.startsz;
2874 endsz = group.endsz;
2876 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2878 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2879 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2880 if(result == GDI_ERROR) {
2881 FIXME("Failed to retrieve vTable\n");
2882 goto end;
2885 if(height > 0) {
2886 for(i = 0; i < recs; i++) {
2887 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2888 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2889 ppem = GET_BE_WORD(vTable[i * 3]);
2891 if(yMax + -yMin == height) {
2892 font->yMax = yMax;
2893 font->yMin = yMin;
2894 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2895 break;
2897 if(yMax + -yMin > height) {
2898 if(--i < 0) {
2899 ppem = 0;
2900 goto end; /* failed */
2902 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2903 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2904 ppem = GET_BE_WORD(vTable[i * 3]);
2905 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2906 break;
2909 if(!font->yMax) {
2910 ppem = 0;
2911 TRACE("ppem not found for height %d\n", height);
2913 } else {
2914 ppem = -height;
2915 if(ppem < startsz || ppem > endsz)
2916 goto end;
2918 for(i = 0; i < recs; i++) {
2919 USHORT yPelHeight;
2920 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2922 if(yPelHeight > ppem)
2923 break; /* failed */
2925 if(yPelHeight == ppem) {
2926 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2927 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2928 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2929 break;
2933 end:
2934 HeapFree(GetProcessHeap(), 0, vTable);
2937 return ppem;
2940 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2942 if(font->font_desc.hash != fd->hash) return TRUE;
2943 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2944 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2945 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2946 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2949 static void calc_hash(FONT_DESC *pfd)
2951 DWORD hash = 0, *ptr, two_chars;
2952 WORD *pwc;
2953 unsigned int i;
2955 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2956 hash ^= *ptr;
2957 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2958 hash ^= *ptr;
2959 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2960 two_chars = *ptr;
2961 pwc = (WCHAR *)&two_chars;
2962 if(!*pwc) break;
2963 *pwc = toupperW(*pwc);
2964 pwc++;
2965 *pwc = toupperW(*pwc);
2966 hash ^= two_chars;
2967 if(!*pwc) break;
2969 hash ^= !pfd->can_use_bitmap;
2970 pfd->hash = hash;
2971 return;
2974 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
2976 GdiFont *ret;
2977 FONT_DESC fd;
2978 HFONTLIST *hflist;
2979 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2981 fd.lf = *plf;
2982 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2983 fd.can_use_bitmap = can_use_bitmap;
2984 calc_hash(&fd);
2986 /* try the in-use list */
2987 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2988 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2989 if(!fontcmp(ret, &fd)) {
2990 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2991 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2992 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2993 if(hflist->hfont == hfont)
2994 return ret;
2996 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2997 hflist->hfont = hfont;
2998 list_add_head(&ret->hfontlist, &hflist->entry);
2999 return ret;
3003 /* then the unused list */
3004 font_elem_ptr = list_head(&unused_gdi_font_list);
3005 while(font_elem_ptr) {
3006 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3007 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3008 if(!fontcmp(ret, &fd)) {
3009 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3010 assert(list_empty(&ret->hfontlist));
3011 TRACE("Found %p in unused list\n", ret);
3012 list_remove(&ret->entry);
3013 list_add_head(&gdi_font_list, &ret->entry);
3014 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3015 hflist->hfont = hfont;
3016 list_add_head(&ret->hfontlist, &hflist->entry);
3017 return ret;
3020 return NULL;
3024 /*************************************************************
3025 * create_child_font_list
3027 static BOOL create_child_font_list(GdiFont *font)
3029 BOOL ret = FALSE;
3030 SYSTEM_LINKS *font_link;
3031 CHILD_FONT *font_link_entry, *new_child;
3033 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3035 if(!strcmpW(font_link->font_name, font->name))
3037 TRACE("found entry in system list\n");
3038 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3040 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3041 new_child->face = font_link_entry->face;
3042 new_child->font = NULL;
3043 list_add_tail(&font->child_fonts, &new_child->entry);
3044 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3046 ret = TRUE;
3047 break;
3051 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3052 * Sans Serif. This is how asian windows get default fallbacks for fonts
3054 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3055 font->charset != OEM_CHARSET &&
3056 strcmpW(font->name,szDefaultFallbackLink) != 0)
3057 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3059 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3061 TRACE("found entry in default fallback list\n");
3062 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3064 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3065 new_child->face = font_link_entry->face;
3066 new_child->font = NULL;
3067 list_add_tail(&font->child_fonts, &new_child->entry);
3068 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3070 ret = TRUE;
3071 break;
3075 return ret;
3078 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3080 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3082 if (pFT_Set_Charmap)
3084 FT_Int i;
3085 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3087 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3089 for (i = 0; i < ft_face->num_charmaps; i++)
3091 if (ft_face->charmaps[i]->encoding == encoding)
3093 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3094 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3096 switch (ft_face->charmaps[i]->platform_id)
3098 default:
3099 cmap_def = ft_face->charmaps[i];
3100 break;
3101 case 0: /* Apple Unicode */
3102 cmap0 = ft_face->charmaps[i];
3103 break;
3104 case 1: /* Macintosh */
3105 cmap1 = ft_face->charmaps[i];
3106 break;
3107 case 2: /* ISO */
3108 cmap2 = ft_face->charmaps[i];
3109 break;
3110 case 3: /* Microsoft */
3111 cmap3 = ft_face->charmaps[i];
3112 break;
3116 if (cmap3) /* prefer Microsoft cmap table */
3117 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3118 else if (cmap1)
3119 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3120 else if (cmap2)
3121 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3122 else if (cmap0)
3123 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3124 else if (cmap_def)
3125 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3127 return ft_err == FT_Err_Ok;
3130 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3133 /*************************************************************
3134 * WineEngCreateFontInstance
3137 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3139 GdiFont *ret;
3140 Face *face, *best, *best_bitmap;
3141 Family *family, *last_resort_family;
3142 struct list *family_elem_ptr, *face_elem_ptr;
3143 INT height, width = 0;
3144 unsigned int score = 0, new_score;
3145 signed int diff = 0, newdiff;
3146 BOOL bd, it, can_use_bitmap;
3147 LOGFONTW lf;
3148 CHARSETINFO csi;
3149 HFONTLIST *hflist;
3151 EnterCriticalSection( &freetype_cs );
3153 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3155 struct list *first_hfont = list_head(&ret->hfontlist);
3156 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3157 if(hflist->hfont == hfont)
3159 LeaveCriticalSection( &freetype_cs );
3160 return ret;
3164 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3166 LeaveCriticalSection( &freetype_cs );
3167 return NULL;
3169 lf.lfWidth = abs(lf.lfWidth);
3171 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3173 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3174 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3175 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3176 lf.lfEscapement);
3178 /* check the cache first */
3179 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3180 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3181 LeaveCriticalSection( &freetype_cs );
3182 return ret;
3185 TRACE("not in cache\n");
3186 if(list_empty(&font_list)) /* No fonts installed */
3188 TRACE("No fonts installed\n");
3189 LeaveCriticalSection( &freetype_cs );
3190 return NULL;
3192 if(!have_installed_roman_font)
3194 TRACE("No roman font installed\n");
3195 LeaveCriticalSection( &freetype_cs );
3196 return NULL;
3199 ret = alloc_font();
3201 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3202 ret->font_desc.lf = lf;
3203 ret->font_desc.can_use_bitmap = can_use_bitmap;
3204 calc_hash(&ret->font_desc);
3205 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3206 hflist->hfont = hfont;
3207 list_add_head(&ret->hfontlist, &hflist->entry);
3210 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3211 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3212 original value lfCharSet. Note this is a special case for
3213 Symbol and doesn't happen at least for "Wingdings*" */
3215 if(!strcmpiW(lf.lfFaceName, SymbolW))
3216 lf.lfCharSet = SYMBOL_CHARSET;
3218 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3219 switch(lf.lfCharSet) {
3220 case DEFAULT_CHARSET:
3221 csi.fs.fsCsb[0] = 0;
3222 break;
3223 default:
3224 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3225 csi.fs.fsCsb[0] = 0;
3226 break;
3230 family = NULL;
3231 if(lf.lfFaceName[0] != '\0') {
3232 FontSubst *psub;
3233 SYSTEM_LINKS *font_link;
3234 CHILD_FONT *font_link_entry;
3235 LPWSTR FaceName = lf.lfFaceName;
3238 * Check for a leading '@' this signals that the font is being
3239 * requested in tategaki mode (vertical writing substitution) but
3240 * does not affect the fontface that is to be selected.
3242 if (lf.lfFaceName[0]=='@')
3243 FaceName = &lf.lfFaceName[1];
3245 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3247 if(psub) {
3248 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3249 debugstr_w(psub->to.name));
3250 strcpyW(FaceName, psub->to.name);
3253 /* We want a match on name and charset or just name if
3254 charset was DEFAULT_CHARSET. If the latter then
3255 we fixup the returned charset later in get_nearest_charset
3256 where we'll either use the charset of the current ansi codepage
3257 or if that's unavailable the first charset that the font supports.
3259 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3260 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3261 if(!strcmpiW(family->FamilyName, FaceName)) {
3262 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3263 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3264 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3265 if(face->scalable || can_use_bitmap)
3266 goto found;
3272 * Try check the SystemLink list first for a replacement font.
3273 * We may find good replacements there.
3275 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3277 if(!strcmpiW(font_link->font_name, FaceName))
3279 TRACE("found entry in system list\n");
3280 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3282 face = font_link_entry->face;
3283 family = face->family;
3284 if(csi.fs.fsCsb[0] &
3285 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3287 if(face->scalable || can_use_bitmap)
3288 goto found;
3295 /* If requested charset was DEFAULT_CHARSET then try using charset
3296 corresponding to the current ansi codepage */
3297 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3299 INT acp = GetACP();
3300 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3301 FIXME("TCI failed on codepage %d\n", acp);
3302 csi.fs.fsCsb[0] = 0;
3303 } else
3304 lf.lfCharSet = csi.ciCharset;
3307 /* Face families are in the top 4 bits of lfPitchAndFamily,
3308 so mask with 0xF0 before testing */
3310 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3311 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3312 strcpyW(lf.lfFaceName, defFixed);
3313 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3314 strcpyW(lf.lfFaceName, defSerif);
3315 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3316 strcpyW(lf.lfFaceName, defSans);
3317 else
3318 strcpyW(lf.lfFaceName, defSans);
3319 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3320 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3321 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3322 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3323 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3324 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3325 if(face->scalable || can_use_bitmap)
3326 goto found;
3331 last_resort_family = NULL;
3332 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3333 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3334 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3335 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3336 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3337 if(face->scalable)
3338 goto found;
3339 if(can_use_bitmap && !last_resort_family)
3340 last_resort_family = family;
3345 if(last_resort_family) {
3346 family = last_resort_family;
3347 csi.fs.fsCsb[0] = 0;
3348 goto found;
3351 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3352 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3353 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3354 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3355 if(face->scalable) {
3356 csi.fs.fsCsb[0] = 0;
3357 WARN("just using first face for now\n");
3358 goto found;
3360 if(can_use_bitmap && !last_resort_family)
3361 last_resort_family = family;
3364 if(!last_resort_family) {
3365 FIXME("can't find a single appropriate font - bailing\n");
3366 free_font(ret);
3367 LeaveCriticalSection( &freetype_cs );
3368 return NULL;
3371 WARN("could only find a bitmap font - this will probably look awful!\n");
3372 family = last_resort_family;
3373 csi.fs.fsCsb[0] = 0;
3375 found:
3376 it = lf.lfItalic ? 1 : 0;
3377 bd = lf.lfWeight > 550 ? 1 : 0;
3379 height = GDI_ROUND( (double)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3380 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3382 face = best = best_bitmap = NULL;
3383 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3385 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3387 BOOL italic, bold;
3389 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3390 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3391 new_score = (italic ^ it) + (bold ^ bd);
3392 if(!best || new_score <= score)
3394 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3395 italic, bold, it, bd);
3396 score = new_score;
3397 best = face;
3398 if(best->scalable && score == 0) break;
3399 if(!best->scalable)
3401 if(height > 0)
3402 newdiff = height - (signed int)(best->size.height);
3403 else
3404 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3405 if(!best_bitmap || new_score < score ||
3406 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3408 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3409 diff = newdiff;
3410 best_bitmap = best;
3411 if(score == 0 && diff == 0) break;
3417 if(best)
3418 face = best->scalable ? best : best_bitmap;
3419 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3420 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3422 ret->fs = face->fs;
3424 if(csi.fs.fsCsb[0]) {
3425 ret->charset = lf.lfCharSet;
3426 ret->codepage = csi.ciACP;
3428 else
3429 ret->charset = get_nearest_charset(face, &ret->codepage);
3431 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3432 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3434 ret->aveWidth = height ? lf.lfWidth : 0;
3436 if(!face->scalable) {
3437 /* Windows uses integer scaling factors for bitmap fonts */
3438 INT scale, scaled_height;
3440 if (height != 0) height = diff;
3441 height += face->size.height;
3443 scale = (height + face->size.height - 1) / face->size.height;
3444 scaled_height = scale * face->size.height;
3445 /* XP allows not more than 10% deviation */
3446 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3447 ret->scale_y = scale;
3449 width = face->size.x_ppem >> 6;
3450 height = face->size.y_ppem >> 6;
3452 else
3453 ret->scale_y = 1.0;
3454 TRACE("font scale y: %f\n", ret->scale_y);
3456 ret->ft_face = OpenFontFace(ret, face, width, height);
3458 if (!ret->ft_face)
3460 free_font( ret );
3461 LeaveCriticalSection( &freetype_cs );
3462 return 0;
3465 ret->ntmFlags = face->ntmFlags;
3467 if (ret->charset == SYMBOL_CHARSET &&
3468 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3469 /* No ops */
3471 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3472 /* No ops */
3474 else {
3475 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3478 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3479 ret->name = strdupW(family->FamilyName);
3480 ret->underline = lf.lfUnderline ? 0xff : 0;
3481 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3482 create_child_font_list(ret);
3484 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3486 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3487 if (length != GDI_ERROR)
3489 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3490 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3491 TRACE("Loaded GSUB table of %i bytes\n",length);
3495 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3497 list_add_head(&gdi_font_list, &ret->entry);
3498 LeaveCriticalSection( &freetype_cs );
3499 return ret;
3502 static void dump_gdi_font_list(void)
3504 GdiFont *gdiFont;
3505 struct list *elem_ptr;
3507 TRACE("---------- gdiFont Cache ----------\n");
3508 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3509 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3510 TRACE("gdiFont=%p %s %d\n",
3511 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3514 TRACE("---------- Unused gdiFont Cache ----------\n");
3515 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3516 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3517 TRACE("gdiFont=%p %s %d\n",
3518 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3522 /*************************************************************
3523 * WineEngDestroyFontInstance
3525 * free the gdiFont associated with this handle
3528 BOOL WineEngDestroyFontInstance(HFONT handle)
3530 GdiFont *gdiFont;
3531 HFONTLIST *hflist;
3532 BOOL ret = FALSE;
3533 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3534 int i = 0;
3536 EnterCriticalSection( &freetype_cs );
3538 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3540 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3541 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3542 if(hflist->hfont == handle)
3544 TRACE("removing child font %p from child list\n", gdiFont);
3545 list_remove(&gdiFont->entry);
3546 LeaveCriticalSection( &freetype_cs );
3547 return TRUE;
3551 TRACE("destroying hfont=%p\n", handle);
3552 if(TRACE_ON(font))
3553 dump_gdi_font_list();
3555 font_elem_ptr = list_head(&gdi_font_list);
3556 while(font_elem_ptr) {
3557 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3558 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3560 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3561 while(hfontlist_elem_ptr) {
3562 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3563 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3564 if(hflist->hfont == handle) {
3565 list_remove(&hflist->entry);
3566 HeapFree(GetProcessHeap(), 0, hflist);
3567 ret = TRUE;
3570 if(list_empty(&gdiFont->hfontlist)) {
3571 TRACE("Moving to Unused list\n");
3572 list_remove(&gdiFont->entry);
3573 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3578 font_elem_ptr = list_head(&unused_gdi_font_list);
3579 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3580 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3581 while(font_elem_ptr) {
3582 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3583 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3584 TRACE("freeing %p\n", gdiFont);
3585 list_remove(&gdiFont->entry);
3586 free_font(gdiFont);
3588 LeaveCriticalSection( &freetype_cs );
3589 return ret;
3592 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3593 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3595 GdiFont *font;
3596 LONG width, height;
3598 if (face->cached_enum_data)
3600 TRACE("Cached\n");
3601 *pelf = face->cached_enum_data->elf;
3602 *pntm = face->cached_enum_data->ntm;
3603 *ptype = face->cached_enum_data->type;
3604 return;
3607 font = alloc_font();
3609 if(face->scalable) {
3610 height = -2048; /* 2048 is the most common em size */
3611 width = 0;
3612 } else {
3613 height = face->size.y_ppem >> 6;
3614 width = face->size.x_ppem >> 6;
3616 font->scale_y = 1.0;
3618 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3620 free_font(font);
3621 return;
3624 font->name = strdupW(face->family->FamilyName);
3625 font->ntmFlags = face->ntmFlags;
3627 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3629 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3631 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3633 lstrcpynW(pelf->elfLogFont.lfFaceName,
3634 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3635 LF_FACESIZE);
3636 lstrcpynW(pelf->elfFullName,
3637 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3638 LF_FULLFACESIZE);
3639 lstrcpynW(pelf->elfStyle,
3640 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3641 LF_FACESIZE);
3643 else
3645 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3647 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3649 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3650 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3651 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3654 pntm->ntmTm.ntmFlags = face->ntmFlags;
3655 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3656 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3657 pntm->ntmFontSig = face->fs;
3659 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3661 pelf->elfLogFont.lfEscapement = 0;
3662 pelf->elfLogFont.lfOrientation = 0;
3663 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3664 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3665 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3666 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3667 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3668 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3669 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3670 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3671 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3672 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3673 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3675 *ptype = 0;
3676 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3677 *ptype |= TRUETYPE_FONTTYPE;
3678 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3679 *ptype |= DEVICE_FONTTYPE;
3680 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3681 *ptype |= RASTER_FONTTYPE;
3683 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3684 if (face->cached_enum_data)
3686 face->cached_enum_data->elf = *pelf;
3687 face->cached_enum_data->ntm = *pntm;
3688 face->cached_enum_data->type = *ptype;
3691 free_font(font);
3694 /*************************************************************
3695 * WineEngEnumFonts
3698 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3700 Family *family;
3701 Face *face;
3702 struct list *family_elem_ptr, *face_elem_ptr;
3703 ENUMLOGFONTEXW elf;
3704 NEWTEXTMETRICEXW ntm;
3705 DWORD type;
3706 FONTSIGNATURE fs;
3707 CHARSETINFO csi;
3708 LOGFONTW lf;
3709 int i;
3711 if (!plf)
3713 lf.lfCharSet = DEFAULT_CHARSET;
3714 lf.lfPitchAndFamily = 0;
3715 lf.lfFaceName[0] = 0;
3716 plf = &lf;
3719 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3721 EnterCriticalSection( &freetype_cs );
3722 if(plf->lfFaceName[0]) {
3723 FontSubst *psub;
3724 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3726 if(psub) {
3727 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3728 debugstr_w(psub->to.name));
3729 lf = *plf;
3730 strcpyW(lf.lfFaceName, psub->to.name);
3731 plf = &lf;
3734 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3735 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3736 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3737 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3738 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3739 GetEnumStructs(face, &elf, &ntm, &type);
3740 for(i = 0; i < 32; i++) {
3741 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3742 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3743 strcpyW(elf.elfScript, OEM_DOSW);
3744 i = 32; /* break out of loop */
3745 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3746 continue;
3747 else {
3748 fs.fsCsb[0] = 1L << i;
3749 fs.fsCsb[1] = 0;
3750 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3751 TCI_SRCFONTSIG))
3752 csi.ciCharset = DEFAULT_CHARSET;
3753 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3754 if(csi.ciCharset != DEFAULT_CHARSET) {
3755 elf.elfLogFont.lfCharSet =
3756 ntm.ntmTm.tmCharSet = csi.ciCharset;
3757 if(ElfScriptsW[i])
3758 strcpyW(elf.elfScript, ElfScriptsW[i]);
3759 else
3760 FIXME("Unknown elfscript for bit %d\n", i);
3763 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3764 debugstr_w(elf.elfLogFont.lfFaceName),
3765 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3766 csi.ciCharset, type, debugstr_w(elf.elfScript),
3767 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3768 ntm.ntmTm.ntmFlags);
3769 /* release section before callback (FIXME) */
3770 LeaveCriticalSection( &freetype_cs );
3771 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3772 EnterCriticalSection( &freetype_cs );
3777 } else {
3778 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3779 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3780 face_elem_ptr = list_head(&family->faces);
3781 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3782 GetEnumStructs(face, &elf, &ntm, &type);
3783 for(i = 0; i < 32; i++) {
3784 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3785 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3786 strcpyW(elf.elfScript, OEM_DOSW);
3787 i = 32; /* break out of loop */
3788 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3789 continue;
3790 else {
3791 fs.fsCsb[0] = 1L << i;
3792 fs.fsCsb[1] = 0;
3793 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3794 TCI_SRCFONTSIG))
3795 csi.ciCharset = DEFAULT_CHARSET;
3796 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3797 if(csi.ciCharset != DEFAULT_CHARSET) {
3798 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3799 csi.ciCharset;
3800 if(ElfScriptsW[i])
3801 strcpyW(elf.elfScript, ElfScriptsW[i]);
3802 else
3803 FIXME("Unknown elfscript for bit %d\n", i);
3806 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3807 debugstr_w(elf.elfLogFont.lfFaceName),
3808 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3809 csi.ciCharset, type, debugstr_w(elf.elfScript),
3810 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3811 ntm.ntmTm.ntmFlags);
3812 /* release section before callback (FIXME) */
3813 LeaveCriticalSection( &freetype_cs );
3814 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3815 EnterCriticalSection( &freetype_cs );
3819 LeaveCriticalSection( &freetype_cs );
3820 return 1;
3823 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3825 pt->x.value = vec->x >> 6;
3826 pt->x.fract = (vec->x & 0x3f) << 10;
3827 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3828 pt->y.value = vec->y >> 6;
3829 pt->y.fract = (vec->y & 0x3f) << 10;
3830 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3831 return;
3834 /***************************************************
3835 * According to the MSDN documentation on WideCharToMultiByte,
3836 * certain codepages cannot set the default_used parameter.
3837 * This returns TRUE if the codepage can set that parameter, false else
3838 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3840 static BOOL codepage_sets_default_used(UINT codepage)
3842 switch (codepage)
3844 case CP_UTF7:
3845 case CP_UTF8:
3846 case CP_SYMBOL:
3847 return FALSE;
3848 default:
3849 return TRUE;
3854 * GSUB Table handling functions
3857 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3859 const GSUB_CoverageFormat1* cf1;
3861 cf1 = (GSUB_CoverageFormat1*)table;
3863 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3865 int count = GET_BE_WORD(cf1->GlyphCount);
3866 int i;
3867 TRACE("Coverage Format 1, %i glyphs\n",count);
3868 for (i = 0; i < count; i++)
3869 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3870 return i;
3871 return -1;
3873 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3875 const GSUB_CoverageFormat2* cf2;
3876 int i;
3877 int count;
3878 cf2 = (GSUB_CoverageFormat2*)cf1;
3880 count = GET_BE_WORD(cf2->RangeCount);
3881 TRACE("Coverage Format 2, %i ranges\n",count);
3882 for (i = 0; i < count; i++)
3884 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3885 return -1;
3886 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3887 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3889 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3890 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3893 return -1;
3895 else
3896 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3898 return -1;
3901 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3903 const GSUB_ScriptList *script;
3904 const GSUB_Script *deflt = NULL;
3905 int i;
3906 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3908 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3909 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3911 const GSUB_Script *scr;
3912 int offset;
3914 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3915 scr = (GSUB_Script*)((LPBYTE)script + offset);
3917 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3918 return scr;
3919 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3920 deflt = scr;
3922 return deflt;
3925 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3927 int i;
3928 int offset;
3929 const GSUB_LangSys *Lang;
3931 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3933 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3935 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3936 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3938 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3939 return Lang;
3941 offset = GET_BE_WORD(script->DefaultLangSys);
3942 if (offset)
3944 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3945 return Lang;
3947 return NULL;
3950 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3952 int i;
3953 const GSUB_FeatureList *feature;
3954 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3956 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
3957 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3959 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3960 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3962 const GSUB_Feature *feat;
3963 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3964 return feat;
3967 return NULL;
3970 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3972 int i;
3973 int offset;
3974 const GSUB_LookupList *lookup;
3975 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3977 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3978 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3980 const GSUB_LookupTable *look;
3981 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3982 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3983 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3984 if (GET_BE_WORD(look->LookupType) != 1)
3985 FIXME("We only handle SubType 1\n");
3986 else
3988 int j;
3990 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3992 const GSUB_SingleSubstFormat1 *ssf1;
3993 offset = GET_BE_WORD(look->SubTable[j]);
3994 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3995 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3997 int offset = GET_BE_WORD(ssf1->Coverage);
3998 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
3999 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4001 TRACE(" Glyph 0x%x ->",glyph);
4002 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4003 TRACE(" 0x%x\n",glyph);
4006 else
4008 const GSUB_SingleSubstFormat2 *ssf2;
4009 INT index;
4010 INT offset;
4012 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4013 offset = GET_BE_WORD(ssf1->Coverage);
4014 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4015 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4016 TRACE(" Coverage index %i\n",index);
4017 if (index != -1)
4019 TRACE(" Glyph is 0x%x ->",glyph);
4020 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4021 TRACE("0x%x\n",glyph);
4027 return glyph;
4030 static const char* get_opentype_script(const GdiFont *font)
4033 * I am not sure if this is the correct way to generate our script tag
4036 switch (font->charset)
4038 case ANSI_CHARSET: return "latn";
4039 case BALTIC_CHARSET: return "latn"; /* ?? */
4040 case CHINESEBIG5_CHARSET: return "hani";
4041 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4042 case GB2312_CHARSET: return "hani";
4043 case GREEK_CHARSET: return "grek";
4044 case HANGUL_CHARSET: return "hang";
4045 case RUSSIAN_CHARSET: return "cyrl";
4046 case SHIFTJIS_CHARSET: return "kana";
4047 case TURKISH_CHARSET: return "latn"; /* ?? */
4048 case VIETNAMESE_CHARSET: return "latn";
4049 case JOHAB_CHARSET: return "latn"; /* ?? */
4050 case ARABIC_CHARSET: return "arab";
4051 case HEBREW_CHARSET: return "hebr";
4052 case THAI_CHARSET: return "thai";
4053 default: return "latn";
4057 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4059 const GSUB_Header *header;
4060 const GSUB_Script *script;
4061 const GSUB_LangSys *language;
4062 const GSUB_Feature *feature;
4064 if (!font->GSUB_Table)
4065 return glyph;
4067 header = font->GSUB_Table;
4069 script = GSUB_get_script_table(header, get_opentype_script(font));
4070 if (!script)
4072 TRACE("Script not found\n");
4073 return glyph;
4075 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4076 if (!language)
4078 TRACE("Language not found\n");
4079 return glyph;
4081 feature = GSUB_get_feature(header, language, "vrt2");
4082 if (!feature)
4083 feature = GSUB_get_feature(header, language, "vert");
4084 if (!feature)
4086 TRACE("vrt2/vert feature not found\n");
4087 return glyph;
4089 return GSUB_apply_feature(header, feature, glyph);
4092 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4094 FT_UInt glyphId;
4096 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4097 WCHAR wc = (WCHAR)glyph;
4098 BOOL default_used;
4099 BOOL *default_used_pointer;
4100 FT_UInt ret;
4101 char buf;
4102 default_used_pointer = NULL;
4103 default_used = FALSE;
4104 if (codepage_sets_default_used(font->codepage))
4105 default_used_pointer = &default_used;
4106 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4107 ret = 0;
4108 else
4109 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4110 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4111 return get_GSUB_vert_glyph(font,ret);
4114 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4115 glyph = glyph + 0xf000;
4116 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4117 return get_GSUB_vert_glyph(font,glyphId);
4120 /*************************************************************
4121 * WineEngGetGlyphIndices
4124 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4125 LPWORD pgi, DWORD flags)
4127 int i;
4128 int default_char = -1;
4130 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4132 for(i = 0; i < count; i++)
4134 pgi[i] = get_glyph_index(font, lpstr[i]);
4135 if (pgi[i] == 0)
4137 if (default_char == -1)
4139 if (FT_IS_SFNT(font->ft_face))
4141 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4142 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4144 else
4146 TEXTMETRICW textm;
4147 WineEngGetTextMetrics(font, &textm);
4148 default_char = textm.tmDefaultChar;
4151 pgi[i] = default_char;
4154 return count;
4157 /*************************************************************
4158 * WineEngGetGlyphOutline
4160 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4161 * except that the first parameter is the HWINEENGFONT of the font in
4162 * question rather than an HDC.
4165 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4166 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4167 const MAT2* lpmat)
4169 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4170 FT_Face ft_face = incoming_font->ft_face;
4171 GdiFont *font = incoming_font;
4172 FT_UInt glyph_index;
4173 DWORD width, height, pitch, needed = 0;
4174 FT_Bitmap ft_bitmap;
4175 FT_Error err;
4176 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4177 FT_Angle angle = 0;
4178 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4179 float widthRatio = 1.0;
4180 FT_Matrix transMat = identityMat;
4181 BOOL needsTransform = FALSE;
4182 BOOL tategaki = (font->GSUB_Table != NULL);
4183 UINT original_index;
4186 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4187 buflen, buf, lpmat);
4189 EnterCriticalSection( &freetype_cs );
4191 if(format & GGO_GLYPH_INDEX) {
4192 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4193 original_index = glyph;
4194 format &= ~GGO_GLYPH_INDEX;
4195 } else {
4196 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4197 ft_face = font->ft_face;
4198 original_index = glyph_index;
4201 /* tategaki never appears to happen to lower glyph index */
4202 if (glyph_index < TATEGAKI_LOWER_BOUND )
4203 tategaki = FALSE;
4205 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4206 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4207 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4208 font->gmsize * sizeof(GM*));
4209 } else {
4210 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4211 *lpgm = FONT_GM(font,original_index)->gm;
4212 LeaveCriticalSection( &freetype_cs );
4213 return 1; /* FIXME */
4217 if (!font->gm[original_index / GM_BLOCK_SIZE])
4218 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4220 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4221 load_flags |= FT_LOAD_NO_BITMAP;
4223 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4225 if(err) {
4226 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4227 LeaveCriticalSection( &freetype_cs );
4228 return GDI_ERROR;
4231 /* Scaling factor */
4232 if (font->aveWidth && font->potm)
4234 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4235 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4237 else
4238 widthRatio = font->scale_y;
4240 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4241 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4243 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4244 lsb = left >> 6;
4245 bbx = (right - left) >> 6;
4247 /* Scaling transform */
4248 if(font->aveWidth) {
4249 FT_Matrix scaleMat;
4250 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4251 scaleMat.xy = 0;
4252 scaleMat.yx = 0;
4253 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4255 pFT_Matrix_Multiply(&scaleMat, &transMat);
4256 needsTransform = TRUE;
4259 /* Slant transform */
4260 if (font->fake_italic) {
4261 FT_Matrix slantMat;
4263 slantMat.xx = (1 << 16);
4264 slantMat.xy = ((1 << 16) >> 2);
4265 slantMat.yx = 0;
4266 slantMat.yy = (1 << 16);
4267 pFT_Matrix_Multiply(&slantMat, &transMat);
4268 needsTransform = TRUE;
4271 /* Rotation transform */
4272 if(font->orientation && !tategaki) {
4273 FT_Matrix rotationMat;
4274 FT_Vector vecAngle;
4275 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4276 pFT_Vector_Unit(&vecAngle, angle);
4277 rotationMat.xx = vecAngle.x;
4278 rotationMat.xy = -vecAngle.y;
4279 rotationMat.yx = -rotationMat.xy;
4280 rotationMat.yy = rotationMat.xx;
4282 pFT_Matrix_Multiply(&rotationMat, &transMat);
4283 needsTransform = TRUE;
4286 /* Extra transformation specified by caller */
4287 if (lpmat) {
4288 FT_Matrix extraMat;
4289 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4290 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4291 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4292 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4293 pFT_Matrix_Multiply(&extraMat, &transMat);
4294 needsTransform = TRUE;
4297 if(!needsTransform) {
4298 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4299 bottom = (ft_face->glyph->metrics.horiBearingY -
4300 ft_face->glyph->metrics.height) & -64;
4301 lpgm->gmCellIncX = adv;
4302 lpgm->gmCellIncY = 0;
4303 } else {
4304 INT xc, yc;
4305 FT_Vector vec;
4306 for(xc = 0; xc < 2; xc++) {
4307 for(yc = 0; yc < 2; yc++) {
4308 vec.x = (ft_face->glyph->metrics.horiBearingX +
4309 xc * ft_face->glyph->metrics.width);
4310 vec.y = ft_face->glyph->metrics.horiBearingY -
4311 yc * ft_face->glyph->metrics.height;
4312 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4313 pFT_Vector_Transform(&vec, &transMat);
4314 if(xc == 0 && yc == 0) {
4315 left = right = vec.x;
4316 top = bottom = vec.y;
4317 } else {
4318 if(vec.x < left) left = vec.x;
4319 else if(vec.x > right) right = vec.x;
4320 if(vec.y < bottom) bottom = vec.y;
4321 else if(vec.y > top) top = vec.y;
4325 left = left & -64;
4326 right = (right + 63) & -64;
4327 bottom = bottom & -64;
4328 top = (top + 63) & -64;
4330 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4331 vec.x = ft_face->glyph->metrics.horiAdvance;
4332 vec.y = 0;
4333 pFT_Vector_Transform(&vec, &transMat);
4334 lpgm->gmCellIncX = (vec.x+63) >> 6;
4335 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4337 lpgm->gmBlackBoxX = (right - left) >> 6;
4338 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4339 lpgm->gmptGlyphOrigin.x = left >> 6;
4340 lpgm->gmptGlyphOrigin.y = top >> 6;
4342 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4344 FONT_GM(font,original_index)->gm = *lpgm;
4345 FONT_GM(font,original_index)->adv = adv;
4346 FONT_GM(font,original_index)->lsb = lsb;
4347 FONT_GM(font,original_index)->bbx = bbx;
4348 FONT_GM(font,original_index)->init = TRUE;
4351 if(format == GGO_METRICS)
4353 LeaveCriticalSection( &freetype_cs );
4354 return 1; /* FIXME */
4357 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4358 TRACE("loaded a bitmap\n");
4359 LeaveCriticalSection( &freetype_cs );
4360 return GDI_ERROR;
4363 switch(format) {
4364 case GGO_BITMAP:
4365 width = lpgm->gmBlackBoxX;
4366 height = lpgm->gmBlackBoxY;
4367 pitch = ((width + 31) >> 5) << 2;
4368 needed = pitch * height;
4370 if(!buf || !buflen) break;
4372 switch(ft_face->glyph->format) {
4373 case ft_glyph_format_bitmap:
4375 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4376 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4377 INT h = ft_face->glyph->bitmap.rows;
4378 while(h--) {
4379 memcpy(dst, src, w);
4380 src += ft_face->glyph->bitmap.pitch;
4381 dst += pitch;
4383 break;
4386 case ft_glyph_format_outline:
4387 ft_bitmap.width = width;
4388 ft_bitmap.rows = height;
4389 ft_bitmap.pitch = pitch;
4390 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4391 ft_bitmap.buffer = buf;
4393 if(needsTransform) {
4394 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4397 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4399 /* Note: FreeType will only set 'black' bits for us. */
4400 memset(buf, 0, needed);
4401 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4402 break;
4404 default:
4405 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4406 LeaveCriticalSection( &freetype_cs );
4407 return GDI_ERROR;
4409 break;
4411 case GGO_GRAY2_BITMAP:
4412 case GGO_GRAY4_BITMAP:
4413 case GGO_GRAY8_BITMAP:
4414 case WINE_GGO_GRAY16_BITMAP:
4416 unsigned int mult, row, col;
4417 BYTE *start, *ptr;
4419 width = lpgm->gmBlackBoxX;
4420 height = lpgm->gmBlackBoxY;
4421 pitch = (width + 3) / 4 * 4;
4422 needed = pitch * height;
4424 if(!buf || !buflen) break;
4426 switch(ft_face->glyph->format) {
4427 case ft_glyph_format_bitmap:
4429 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4430 INT h = ft_face->glyph->bitmap.rows;
4431 INT x;
4432 while(h--) {
4433 for(x = 0; x < pitch; x++)
4435 if(x < ft_face->glyph->bitmap.width)
4436 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4437 else
4438 dst[x] = 0;
4440 src += ft_face->glyph->bitmap.pitch;
4441 dst += pitch;
4443 LeaveCriticalSection( &freetype_cs );
4444 return needed;
4446 case ft_glyph_format_outline:
4448 ft_bitmap.width = width;
4449 ft_bitmap.rows = height;
4450 ft_bitmap.pitch = pitch;
4451 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4452 ft_bitmap.buffer = buf;
4454 if(needsTransform)
4455 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4457 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4459 memset(ft_bitmap.buffer, 0, buflen);
4461 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4463 if(format == GGO_GRAY2_BITMAP)
4464 mult = 4;
4465 else if(format == GGO_GRAY4_BITMAP)
4466 mult = 16;
4467 else if(format == GGO_GRAY8_BITMAP)
4468 mult = 64;
4469 else /* format == WINE_GGO_GRAY16_BITMAP */
4471 LeaveCriticalSection( &freetype_cs );
4472 return needed;
4474 break;
4476 default:
4477 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4478 LeaveCriticalSection( &freetype_cs );
4479 return GDI_ERROR;
4482 start = buf;
4483 for(row = 0; row < height; row++) {
4484 ptr = start;
4485 for(col = 0; col < width; col++, ptr++) {
4486 *ptr = (((int)*ptr) * mult + 128) / 256;
4488 start += pitch;
4490 break;
4493 case GGO_NATIVE:
4495 int contour, point = 0, first_pt;
4496 FT_Outline *outline = &ft_face->glyph->outline;
4497 TTPOLYGONHEADER *pph;
4498 TTPOLYCURVE *ppc;
4499 DWORD pph_start, cpfx, type;
4501 if(buflen == 0) buf = NULL;
4503 if (needsTransform && buf) {
4504 pFT_Outline_Transform(outline, &transMat);
4507 for(contour = 0; contour < outline->n_contours; contour++) {
4508 pph_start = needed;
4509 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4510 first_pt = point;
4511 if(buf) {
4512 pph->dwType = TT_POLYGON_TYPE;
4513 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4515 needed += sizeof(*pph);
4516 point++;
4517 while(point <= outline->contours[contour]) {
4518 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4519 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4520 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4521 cpfx = 0;
4522 do {
4523 if(buf)
4524 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4525 cpfx++;
4526 point++;
4527 } while(point <= outline->contours[contour] &&
4528 (outline->tags[point] & FT_Curve_Tag_On) ==
4529 (outline->tags[point-1] & FT_Curve_Tag_On));
4530 /* At the end of a contour Windows adds the start point, but
4531 only for Beziers */
4532 if(point > outline->contours[contour] &&
4533 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4534 if(buf)
4535 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4536 cpfx++;
4537 } else if(point <= outline->contours[contour] &&
4538 outline->tags[point] & FT_Curve_Tag_On) {
4539 /* add closing pt for bezier */
4540 if(buf)
4541 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4542 cpfx++;
4543 point++;
4545 if(buf) {
4546 ppc->wType = type;
4547 ppc->cpfx = cpfx;
4549 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4551 if(buf)
4552 pph->cb = needed - pph_start;
4554 break;
4556 case GGO_BEZIER:
4558 /* Convert the quadratic Beziers to cubic Beziers.
4559 The parametric eqn for a cubic Bezier is, from PLRM:
4560 r(t) = at^3 + bt^2 + ct + r0
4561 with the control points:
4562 r1 = r0 + c/3
4563 r2 = r1 + (c + b)/3
4564 r3 = r0 + c + b + a
4566 A quadratic Beizer has the form:
4567 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4569 So equating powers of t leads to:
4570 r1 = 2/3 p1 + 1/3 p0
4571 r2 = 2/3 p1 + 1/3 p2
4572 and of course r0 = p0, r3 = p2
4575 int contour, point = 0, first_pt;
4576 FT_Outline *outline = &ft_face->glyph->outline;
4577 TTPOLYGONHEADER *pph;
4578 TTPOLYCURVE *ppc;
4579 DWORD pph_start, cpfx, type;
4580 FT_Vector cubic_control[4];
4581 if(buflen == 0) buf = NULL;
4583 if (needsTransform && buf) {
4584 pFT_Outline_Transform(outline, &transMat);
4587 for(contour = 0; contour < outline->n_contours; contour++) {
4588 pph_start = needed;
4589 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4590 first_pt = point;
4591 if(buf) {
4592 pph->dwType = TT_POLYGON_TYPE;
4593 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4595 needed += sizeof(*pph);
4596 point++;
4597 while(point <= outline->contours[contour]) {
4598 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4599 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4600 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4601 cpfx = 0;
4602 do {
4603 if(type == TT_PRIM_LINE) {
4604 if(buf)
4605 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4606 cpfx++;
4607 point++;
4608 } else {
4609 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4610 so cpfx = 3n */
4612 /* FIXME: Possible optimization in endpoint calculation
4613 if there are two consecutive curves */
4614 cubic_control[0] = outline->points[point-1];
4615 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4616 cubic_control[0].x += outline->points[point].x + 1;
4617 cubic_control[0].y += outline->points[point].y + 1;
4618 cubic_control[0].x >>= 1;
4619 cubic_control[0].y >>= 1;
4621 if(point+1 > outline->contours[contour])
4622 cubic_control[3] = outline->points[first_pt];
4623 else {
4624 cubic_control[3] = outline->points[point+1];
4625 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4626 cubic_control[3].x += outline->points[point].x + 1;
4627 cubic_control[3].y += outline->points[point].y + 1;
4628 cubic_control[3].x >>= 1;
4629 cubic_control[3].y >>= 1;
4632 /* r1 = 1/3 p0 + 2/3 p1
4633 r2 = 1/3 p2 + 2/3 p1 */
4634 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4635 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4636 cubic_control[2] = cubic_control[1];
4637 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4638 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4639 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4640 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4641 if(buf) {
4642 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4643 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4644 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4646 cpfx += 3;
4647 point++;
4649 } while(point <= outline->contours[contour] &&
4650 (outline->tags[point] & FT_Curve_Tag_On) ==
4651 (outline->tags[point-1] & FT_Curve_Tag_On));
4652 /* At the end of a contour Windows adds the start point,
4653 but only for Beziers and we've already done that.
4655 if(point <= outline->contours[contour] &&
4656 outline->tags[point] & FT_Curve_Tag_On) {
4657 /* This is the closing pt of a bezier, but we've already
4658 added it, so just inc point and carry on */
4659 point++;
4661 if(buf) {
4662 ppc->wType = type;
4663 ppc->cpfx = cpfx;
4665 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4667 if(buf)
4668 pph->cb = needed - pph_start;
4670 break;
4673 default:
4674 FIXME("Unsupported format %d\n", format);
4675 LeaveCriticalSection( &freetype_cs );
4676 return GDI_ERROR;
4678 LeaveCriticalSection( &freetype_cs );
4679 return needed;
4682 static BOOL get_bitmap_text_metrics(GdiFont *font)
4684 FT_Face ft_face = font->ft_face;
4685 #ifdef HAVE_FREETYPE_FTWINFNT_H
4686 FT_WinFNT_HeaderRec winfnt_header;
4687 #endif
4688 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4689 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4690 font->potm->otmSize = size;
4692 #define TM font->potm->otmTextMetrics
4693 #ifdef HAVE_FREETYPE_FTWINFNT_H
4694 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4696 TM.tmHeight = winfnt_header.pixel_height;
4697 TM.tmAscent = winfnt_header.ascent;
4698 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4699 TM.tmInternalLeading = winfnt_header.internal_leading;
4700 TM.tmExternalLeading = winfnt_header.external_leading;
4701 TM.tmAveCharWidth = winfnt_header.avg_width;
4702 TM.tmMaxCharWidth = winfnt_header.max_width;
4703 TM.tmWeight = winfnt_header.weight;
4704 TM.tmOverhang = 0;
4705 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4706 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4707 TM.tmFirstChar = winfnt_header.first_char;
4708 TM.tmLastChar = winfnt_header.last_char;
4709 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4710 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4711 TM.tmItalic = winfnt_header.italic;
4712 TM.tmUnderlined = font->underline;
4713 TM.tmStruckOut = font->strikeout;
4714 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4715 TM.tmCharSet = winfnt_header.charset;
4717 else
4718 #endif
4720 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4721 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4722 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4723 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4724 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4725 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4726 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4727 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4728 TM.tmOverhang = 0;
4729 TM.tmDigitizedAspectX = 96; /* FIXME */
4730 TM.tmDigitizedAspectY = 96; /* FIXME */
4731 TM.tmFirstChar = 1;
4732 TM.tmLastChar = 255;
4733 TM.tmDefaultChar = 32;
4734 TM.tmBreakChar = 32;
4735 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4736 TM.tmUnderlined = font->underline;
4737 TM.tmStruckOut = font->strikeout;
4738 /* NB inverted meaning of TMPF_FIXED_PITCH */
4739 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4740 TM.tmCharSet = font->charset;
4742 #undef TM
4744 return TRUE;
4748 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4750 float scale_x;
4752 if (font->aveWidth)
4754 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4755 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4757 else
4758 scale_x = font->scale_y;
4760 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4761 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4762 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4763 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4764 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4766 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4767 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4770 /*************************************************************
4771 * WineEngGetTextMetrics
4774 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4776 EnterCriticalSection( &freetype_cs );
4777 if(!font->potm) {
4778 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4779 if(!get_bitmap_text_metrics(font))
4781 LeaveCriticalSection( &freetype_cs );
4782 return FALSE;
4785 if(!font->potm)
4787 LeaveCriticalSection( &freetype_cs );
4788 return FALSE;
4790 *ptm = font->potm->otmTextMetrics;
4791 scale_font_metrics(font, ptm);
4792 LeaveCriticalSection( &freetype_cs );
4793 return TRUE;
4797 /*************************************************************
4798 * WineEngGetOutlineTextMetrics
4801 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4802 OUTLINETEXTMETRICW *potm)
4804 FT_Face ft_face = font->ft_face;
4805 UINT needed, lenfam, lensty, ret;
4806 TT_OS2 *pOS2;
4807 TT_HoriHeader *pHori;
4808 TT_Postscript *pPost;
4809 FT_Fixed x_scale, y_scale;
4810 WCHAR *family_nameW, *style_nameW;
4811 static const WCHAR spaceW[] = {' ', '\0'};
4812 char *cp;
4813 INT ascent, descent;
4815 TRACE("font=%p\n", font);
4817 if(!FT_IS_SCALABLE(ft_face))
4818 return 0;
4820 EnterCriticalSection( &freetype_cs );
4822 if(font->potm) {
4823 if(cbSize >= font->potm->otmSize)
4825 memcpy(potm, font->potm, font->potm->otmSize);
4826 scale_font_metrics(font, &potm->otmTextMetrics);
4828 LeaveCriticalSection( &freetype_cs );
4829 return font->potm->otmSize;
4833 needed = sizeof(*potm);
4835 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4836 family_nameW = strdupW(font->name);
4838 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4839 * sizeof(WCHAR);
4840 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4841 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4842 style_nameW, lensty/sizeof(WCHAR));
4844 /* These names should be read from the TT name table */
4846 /* length of otmpFamilyName */
4847 needed += lenfam;
4849 /* length of otmpFaceName */
4850 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
4851 needed += lenfam; /* just the family name */
4852 } else {
4853 needed += lenfam + lensty; /* family + " " + style */
4856 /* length of otmpStyleName */
4857 needed += lensty;
4859 /* length of otmpFullName */
4860 needed += lenfam + lensty;
4863 x_scale = ft_face->size->metrics.x_scale;
4864 y_scale = ft_face->size->metrics.y_scale;
4866 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4867 if(!pOS2) {
4868 FIXME("Can't find OS/2 table - not TT font?\n");
4869 ret = 0;
4870 goto end;
4873 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4874 if(!pHori) {
4875 FIXME("Can't find HHEA table - not TT font?\n");
4876 ret = 0;
4877 goto end;
4880 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4882 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",
4883 pOS2->usWinAscent, pOS2->usWinDescent,
4884 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4885 ft_face->ascender, ft_face->descender, ft_face->height,
4886 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4887 ft_face->bbox.yMax, ft_face->bbox.yMin);
4889 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4890 font->potm->otmSize = needed;
4892 #define TM font->potm->otmTextMetrics
4894 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4895 ascent = pHori->Ascender;
4896 descent = -pHori->Descender;
4897 } else {
4898 ascent = pOS2->usWinAscent;
4899 descent = pOS2->usWinDescent;
4902 if(font->yMax) {
4903 TM.tmAscent = font->yMax;
4904 TM.tmDescent = -font->yMin;
4905 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4906 } else {
4907 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4908 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4909 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4910 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4913 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4915 /* MSDN says:
4916 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4918 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4919 ((ascent + descent) -
4920 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4922 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4923 if (TM.tmAveCharWidth == 0) {
4924 TM.tmAveCharWidth = 1;
4926 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4927 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4928 TM.tmOverhang = 0;
4929 TM.tmDigitizedAspectX = 300;
4930 TM.tmDigitizedAspectY = 300;
4931 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4932 * symbol range to 0 - f0ff
4934 if (font->charset == SYMBOL_CHARSET)
4936 TM.tmFirstChar = 0;
4937 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4939 else
4941 TM.tmFirstChar = pOS2->usFirstCharIndex;
4942 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
4944 TM.tmLastChar = pOS2->usLastCharIndex;
4945 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4946 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4947 TM.tmUnderlined = font->underline;
4948 TM.tmStruckOut = font->strikeout;
4950 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4951 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4952 (pOS2->version == 0xFFFFU ||
4953 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4954 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4955 else
4956 TM.tmPitchAndFamily = 0;
4958 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4959 case PAN_FAMILY_SCRIPT:
4960 TM.tmPitchAndFamily |= FF_SCRIPT;
4961 break;
4962 case PAN_FAMILY_DECORATIVE:
4963 case PAN_FAMILY_PICTORIAL:
4964 TM.tmPitchAndFamily |= FF_DECORATIVE;
4965 break;
4966 case PAN_FAMILY_TEXT_DISPLAY:
4967 if(TM.tmPitchAndFamily == 0) /* fixed */
4968 TM.tmPitchAndFamily = FF_MODERN;
4969 else {
4970 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4971 case PAN_SERIF_NORMAL_SANS:
4972 case PAN_SERIF_OBTUSE_SANS:
4973 case PAN_SERIF_PERP_SANS:
4974 TM.tmPitchAndFamily |= FF_SWISS;
4975 break;
4976 default:
4977 TM.tmPitchAndFamily |= FF_ROMAN;
4980 break;
4981 default:
4982 TM.tmPitchAndFamily |= FF_DONTCARE;
4985 if(FT_IS_SCALABLE(ft_face))
4986 TM.tmPitchAndFamily |= TMPF_VECTOR;
4988 if(FT_IS_SFNT(ft_face))
4990 if (font->ntmFlags & NTM_PS_OPENTYPE)
4991 TM.tmPitchAndFamily |= TMPF_DEVICE;
4992 else
4993 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4996 TM.tmCharSet = font->charset;
4997 #undef TM
4999 font->potm->otmFiller = 0;
5000 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5001 font->potm->otmfsSelection = pOS2->fsSelection;
5002 font->potm->otmfsType = pOS2->fsType;
5003 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5004 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5005 font->potm->otmItalicAngle = 0; /* POST table */
5006 font->potm->otmEMSquare = ft_face->units_per_EM;
5007 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5008 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5009 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5010 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5011 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5012 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5013 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5014 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5015 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5016 font->potm->otmMacAscent = 0; /* where do these come from ? */
5017 font->potm->otmMacDescent = 0;
5018 font->potm->otmMacLineGap = 0;
5019 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5020 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5021 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5022 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5023 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5024 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5025 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5026 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5027 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5028 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5029 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5030 if(!pPost) {
5031 font->potm->otmsUnderscoreSize = 0;
5032 font->potm->otmsUnderscorePosition = 0;
5033 } else {
5034 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5035 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5038 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5039 cp = (char*)font->potm + sizeof(*font->potm);
5040 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5041 strcpyW((WCHAR*)cp, family_nameW);
5042 cp += lenfam;
5043 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5044 strcpyW((WCHAR*)cp, style_nameW);
5045 cp += lensty;
5046 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5047 strcpyW((WCHAR*)cp, family_nameW);
5048 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5049 strcatW((WCHAR*)cp, spaceW);
5050 strcatW((WCHAR*)cp, style_nameW);
5051 cp += lenfam + lensty;
5052 } else
5053 cp += lenfam;
5054 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5055 strcpyW((WCHAR*)cp, family_nameW);
5056 strcatW((WCHAR*)cp, spaceW);
5057 strcatW((WCHAR*)cp, style_nameW);
5058 ret = needed;
5060 if(potm && needed <= cbSize)
5062 memcpy(potm, font->potm, font->potm->otmSize);
5063 scale_font_metrics(font, &potm->otmTextMetrics);
5066 end:
5067 HeapFree(GetProcessHeap(), 0, style_nameW);
5068 HeapFree(GetProcessHeap(), 0, family_nameW);
5070 LeaveCriticalSection( &freetype_cs );
5071 return ret;
5074 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5076 HFONTLIST *hfontlist;
5077 child->font = alloc_font();
5078 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5079 if(!child->font->ft_face)
5081 free_font(child->font);
5082 child->font = NULL;
5083 return FALSE;
5086 child->font->ntmFlags = child->face->ntmFlags;
5087 child->font->orientation = font->orientation;
5088 child->font->scale_y = font->scale_y;
5089 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5090 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5091 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5092 child->font->base_font = font;
5093 list_add_head(&child_font_list, &child->font->entry);
5094 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5095 return TRUE;
5098 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5100 FT_UInt g;
5101 CHILD_FONT *child_font;
5103 if(font->base_font)
5104 font = font->base_font;
5106 *linked_font = font;
5108 if((*glyph = get_glyph_index(font, c)))
5109 return TRUE;
5111 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5113 if(!child_font->font)
5114 if(!load_child_font(font, child_font))
5115 continue;
5117 if(!child_font->font->ft_face)
5118 continue;
5119 g = get_glyph_index(child_font->font, c);
5120 if(g)
5122 *glyph = g;
5123 *linked_font = child_font->font;
5124 return TRUE;
5127 return FALSE;
5130 /*************************************************************
5131 * WineEngGetCharWidth
5134 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5135 LPINT buffer)
5137 UINT c;
5138 GLYPHMETRICS gm;
5139 FT_UInt glyph_index;
5140 GdiFont *linked_font;
5142 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5144 EnterCriticalSection( &freetype_cs );
5145 for(c = firstChar; c <= lastChar; c++) {
5146 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5147 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5148 &gm, 0, NULL, NULL);
5149 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5151 LeaveCriticalSection( &freetype_cs );
5152 return TRUE;
5155 /*************************************************************
5156 * WineEngGetCharABCWidths
5159 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5160 LPABC buffer)
5162 UINT c;
5163 GLYPHMETRICS gm;
5164 FT_UInt glyph_index;
5165 GdiFont *linked_font;
5167 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5169 if(!FT_IS_SCALABLE(font->ft_face))
5170 return FALSE;
5172 EnterCriticalSection( &freetype_cs );
5174 for(c = firstChar; c <= lastChar; c++) {
5175 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5176 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5177 &gm, 0, NULL, NULL);
5178 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5179 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5180 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5181 FONT_GM(linked_font,glyph_index)->bbx;
5183 LeaveCriticalSection( &freetype_cs );
5184 return TRUE;
5187 /*************************************************************
5188 * WineEngGetCharABCWidthsI
5191 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5192 LPABC buffer)
5194 UINT c;
5195 GLYPHMETRICS gm;
5196 FT_UInt glyph_index;
5197 GdiFont *linked_font;
5199 if(!FT_HAS_HORIZONTAL(font->ft_face))
5200 return FALSE;
5202 EnterCriticalSection( &freetype_cs );
5204 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5205 if (!pgi)
5206 for(c = firstChar; c < firstChar+count; c++) {
5207 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5208 &gm, 0, NULL, NULL);
5209 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5210 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5211 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5212 - FONT_GM(linked_font,c)->bbx;
5214 else
5215 for(c = 0; c < count; c++) {
5216 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5217 &gm, 0, NULL, NULL);
5218 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5219 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5220 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5221 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5224 LeaveCriticalSection( &freetype_cs );
5225 return TRUE;
5228 /*************************************************************
5229 * WineEngGetTextExtentExPoint
5232 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5233 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5235 INT idx;
5236 INT nfit = 0, ext;
5237 GLYPHMETRICS gm;
5238 TEXTMETRICW tm;
5239 FT_UInt glyph_index;
5240 GdiFont *linked_font;
5242 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5243 max_ext, size);
5245 EnterCriticalSection( &freetype_cs );
5247 size->cx = 0;
5248 WineEngGetTextMetrics(font, &tm);
5249 size->cy = tm.tmHeight;
5251 for(idx = 0; idx < count; idx++) {
5252 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5253 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5254 &gm, 0, NULL, NULL);
5255 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5256 ext = size->cx;
5257 if (! pnfit || ext <= max_ext) {
5258 ++nfit;
5259 if (dxs)
5260 dxs[idx] = ext;
5264 if (pnfit)
5265 *pnfit = nfit;
5267 LeaveCriticalSection( &freetype_cs );
5268 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5269 return TRUE;
5272 /*************************************************************
5273 * WineEngGetTextExtentExPointI
5276 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5277 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5279 INT idx;
5280 INT nfit = 0, ext;
5281 GLYPHMETRICS gm;
5282 TEXTMETRICW tm;
5284 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5286 EnterCriticalSection( &freetype_cs );
5288 size->cx = 0;
5289 WineEngGetTextMetrics(font, &tm);
5290 size->cy = tm.tmHeight;
5292 for(idx = 0; idx < count; idx++) {
5293 WineEngGetGlyphOutline(font, indices[idx],
5294 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5295 NULL);
5296 size->cx += FONT_GM(font,indices[idx])->adv;
5297 ext = size->cx;
5298 if (! pnfit || ext <= max_ext) {
5299 ++nfit;
5300 if (dxs)
5301 dxs[idx] = ext;
5305 if (pnfit)
5306 *pnfit = nfit;
5308 LeaveCriticalSection( &freetype_cs );
5309 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5310 return TRUE;
5313 /*************************************************************
5314 * WineEngGetFontData
5317 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5318 DWORD cbData)
5320 FT_Face ft_face = font->ft_face;
5321 FT_ULong len;
5322 FT_Error err;
5324 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5325 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5326 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5328 if(!FT_IS_SFNT(ft_face))
5329 return GDI_ERROR;
5331 if(!buf || !cbData)
5332 len = 0;
5333 else
5334 len = cbData;
5336 if(table) { /* MS tags differ in endianness from FT ones */
5337 table = table >> 24 | table << 24 |
5338 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5341 /* make sure value of len is the value freetype says it needs */
5342 if(buf && len)
5344 FT_ULong needed = 0;
5345 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5346 if( !err && needed < len) len = needed;
5348 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5350 if(err) {
5351 TRACE("Can't find table %c%c%c%c\n",
5352 /* bytes were reversed */
5353 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5354 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5355 return GDI_ERROR;
5357 return len;
5360 /*************************************************************
5361 * WineEngGetTextFace
5364 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5366 if(str) {
5367 lstrcpynW(str, font->name, count);
5368 return strlenW(font->name);
5369 } else
5370 return strlenW(font->name) + 1;
5373 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5375 if (fs) *fs = font->fs;
5376 return font->charset;
5379 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5381 GdiFont *font = dc->gdiFont, *linked_font;
5382 struct list *first_hfont;
5383 BOOL ret;
5385 EnterCriticalSection( &freetype_cs );
5386 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5387 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5388 if(font == linked_font)
5389 *new_hfont = dc->hFont;
5390 else
5392 first_hfont = list_head(&linked_font->hfontlist);
5393 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5395 LeaveCriticalSection( &freetype_cs );
5396 return ret;
5399 /* Retrieve a list of supported Unicode ranges for a given font.
5400 * Can be called with NULL gs to calculate the buffer size. Returns
5401 * the number of ranges found.
5403 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5405 DWORD num_ranges = 0;
5407 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5409 FT_UInt glyph_code;
5410 FT_ULong char_code, char_code_prev;
5412 glyph_code = 0;
5413 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5415 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5416 face->num_glyphs, glyph_code, char_code);
5418 if (!glyph_code) return 0;
5420 if (gs)
5422 gs->ranges[0].wcLow = (USHORT)char_code;
5423 gs->ranges[0].cGlyphs = 0;
5424 gs->cGlyphsSupported = 0;
5427 num_ranges = 1;
5428 while (glyph_code)
5430 if (char_code < char_code_prev)
5432 ERR("expected increasing char code from FT_Get_Next_Char\n");
5433 return 0;
5435 if (char_code - char_code_prev > 1)
5437 num_ranges++;
5438 if (gs)
5440 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5441 gs->ranges[num_ranges - 1].cGlyphs = 1;
5442 gs->cGlyphsSupported++;
5445 else if (gs)
5447 gs->ranges[num_ranges - 1].cGlyphs++;
5448 gs->cGlyphsSupported++;
5450 char_code_prev = char_code;
5451 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5454 else
5455 FIXME("encoding %u not supported\n", face->charmap->encoding);
5457 return num_ranges;
5460 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5462 DWORD size = 0;
5463 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5465 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5466 if (glyphset)
5468 glyphset->cbThis = size;
5469 glyphset->cRanges = num_ranges;
5471 return size;
5474 /*************************************************************
5475 * FontIsLinked
5477 BOOL WineEngFontIsLinked(GdiFont *font)
5479 BOOL ret;
5480 EnterCriticalSection( &freetype_cs );
5481 ret = !list_empty(&font->child_fonts);
5482 LeaveCriticalSection( &freetype_cs );
5483 return ret;
5486 static BOOL is_hinting_enabled(void)
5488 /* Use the >= 2.2.0 function if available */
5489 if(pFT_Get_TrueType_Engine_Type)
5491 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5492 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5494 #ifdef FT_DRIVER_HAS_HINTER
5495 else
5497 FT_Module mod;
5499 /* otherwise if we've been compiled with < 2.2.0 headers
5500 use the internal macro */
5501 mod = pFT_Get_Module(library, "truetype");
5502 if(mod && FT_DRIVER_HAS_HINTER(mod))
5503 return TRUE;
5505 #endif
5507 return FALSE;
5510 /*************************************************************************
5511 * GetRasterizerCaps (GDI32.@)
5513 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5515 static int hinting = -1;
5517 if(hinting == -1)
5519 hinting = is_hinting_enabled();
5520 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5523 lprs->nSize = sizeof(RASTERIZER_STATUS);
5524 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5525 lprs->nLanguageID = 0;
5526 return TRUE;
5529 /*************************************************************************
5530 * Kerning support for TrueType fonts
5532 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5534 struct TT_kern_table
5536 USHORT version;
5537 USHORT nTables;
5540 struct TT_kern_subtable
5542 USHORT version;
5543 USHORT length;
5544 union
5546 USHORT word;
5547 struct
5549 USHORT horizontal : 1;
5550 USHORT minimum : 1;
5551 USHORT cross_stream: 1;
5552 USHORT override : 1;
5553 USHORT reserved1 : 4;
5554 USHORT format : 8;
5555 } bits;
5556 } coverage;
5559 struct TT_format0_kern_subtable
5561 USHORT nPairs;
5562 USHORT searchRange;
5563 USHORT entrySelector;
5564 USHORT rangeShift;
5567 struct TT_kern_pair
5569 USHORT left;
5570 USHORT right;
5571 short value;
5574 static DWORD parse_format0_kern_subtable(GdiFont *font,
5575 const struct TT_format0_kern_subtable *tt_f0_ks,
5576 const USHORT *glyph_to_char,
5577 KERNINGPAIR *kern_pair, DWORD cPairs)
5579 USHORT i, nPairs;
5580 const struct TT_kern_pair *tt_kern_pair;
5582 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5584 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5586 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5587 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5588 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5590 if (!kern_pair || !cPairs)
5591 return nPairs;
5593 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5595 nPairs = min(nPairs, cPairs);
5597 for (i = 0; i < nPairs; i++)
5599 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5600 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5601 /* this algorithm appears to better match what Windows does */
5602 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5603 if (kern_pair->iKernAmount < 0)
5605 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5606 kern_pair->iKernAmount -= font->ppem;
5608 else if (kern_pair->iKernAmount > 0)
5610 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5611 kern_pair->iKernAmount += font->ppem;
5613 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5615 TRACE("left %u right %u value %d\n",
5616 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5618 kern_pair++;
5620 TRACE("copied %u entries\n", nPairs);
5621 return nPairs;
5624 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5626 DWORD length;
5627 void *buf;
5628 const struct TT_kern_table *tt_kern_table;
5629 const struct TT_kern_subtable *tt_kern_subtable;
5630 USHORT i, nTables;
5631 USHORT *glyph_to_char;
5633 EnterCriticalSection( &freetype_cs );
5634 if (font->total_kern_pairs != (DWORD)-1)
5636 if (cPairs && kern_pair)
5638 cPairs = min(cPairs, font->total_kern_pairs);
5639 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5640 LeaveCriticalSection( &freetype_cs );
5641 return cPairs;
5643 LeaveCriticalSection( &freetype_cs );
5644 return font->total_kern_pairs;
5647 font->total_kern_pairs = 0;
5649 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5651 if (length == GDI_ERROR)
5653 TRACE("no kerning data in the font\n");
5654 LeaveCriticalSection( &freetype_cs );
5655 return 0;
5658 buf = HeapAlloc(GetProcessHeap(), 0, length);
5659 if (!buf)
5661 WARN("Out of memory\n");
5662 LeaveCriticalSection( &freetype_cs );
5663 return 0;
5666 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5668 /* build a glyph index to char code map */
5669 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5670 if (!glyph_to_char)
5672 WARN("Out of memory allocating a glyph index to char code map\n");
5673 HeapFree(GetProcessHeap(), 0, buf);
5674 LeaveCriticalSection( &freetype_cs );
5675 return 0;
5678 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5680 FT_UInt glyph_code;
5681 FT_ULong char_code;
5683 glyph_code = 0;
5684 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5686 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5687 font->ft_face->num_glyphs, glyph_code, char_code);
5689 while (glyph_code)
5691 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5693 /* FIXME: This doesn't match what Windows does: it does some fancy
5694 * things with duplicate glyph index to char code mappings, while
5695 * we just avoid overriding existing entries.
5697 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5698 glyph_to_char[glyph_code] = (USHORT)char_code;
5700 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5703 else
5705 ULONG n;
5707 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5708 for (n = 0; n <= 65535; n++)
5709 glyph_to_char[n] = (USHORT)n;
5712 tt_kern_table = buf;
5713 nTables = GET_BE_WORD(tt_kern_table->nTables);
5714 TRACE("version %u, nTables %u\n",
5715 GET_BE_WORD(tt_kern_table->version), nTables);
5717 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5719 for (i = 0; i < nTables; i++)
5721 struct TT_kern_subtable tt_kern_subtable_copy;
5723 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5724 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5725 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5727 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5728 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5729 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5731 /* According to the TrueType specification this is the only format
5732 * that will be properly interpreted by Windows and OS/2
5734 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5736 DWORD new_chunk, old_total = font->total_kern_pairs;
5738 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5739 glyph_to_char, NULL, 0);
5740 font->total_kern_pairs += new_chunk;
5742 if (!font->kern_pairs)
5743 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5744 font->total_kern_pairs * sizeof(*font->kern_pairs));
5745 else
5746 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5747 font->total_kern_pairs * sizeof(*font->kern_pairs));
5749 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5750 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5752 else
5753 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5755 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5758 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5759 HeapFree(GetProcessHeap(), 0, buf);
5761 if (cPairs && kern_pair)
5763 cPairs = min(cPairs, font->total_kern_pairs);
5764 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5765 LeaveCriticalSection( &freetype_cs );
5766 return cPairs;
5768 LeaveCriticalSection( &freetype_cs );
5769 return font->total_kern_pairs;
5772 #else /* HAVE_FREETYPE */
5774 /*************************************************************************/
5776 BOOL WineEngInit(void)
5778 return FALSE;
5780 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5782 return NULL;
5784 BOOL WineEngDestroyFontInstance(HFONT hfont)
5786 return FALSE;
5789 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5791 return 1;
5794 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5795 LPWORD pgi, DWORD flags)
5797 return GDI_ERROR;
5800 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5801 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5802 const MAT2* lpmat)
5804 ERR("called but we don't have FreeType\n");
5805 return GDI_ERROR;
5808 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5810 ERR("called but we don't have FreeType\n");
5811 return FALSE;
5814 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5815 OUTLINETEXTMETRICW *potm)
5817 ERR("called but we don't have FreeType\n");
5818 return 0;
5821 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5822 LPINT buffer)
5824 ERR("called but we don't have FreeType\n");
5825 return FALSE;
5828 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5829 LPABC buffer)
5831 ERR("called but we don't have FreeType\n");
5832 return FALSE;
5835 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5836 LPABC buffer)
5838 ERR("called but we don't have FreeType\n");
5839 return FALSE;
5842 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5843 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5845 ERR("called but we don't have FreeType\n");
5846 return FALSE;
5849 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5850 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5852 ERR("called but we don't have FreeType\n");
5853 return FALSE;
5856 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5857 DWORD cbData)
5859 ERR("called but we don't have FreeType\n");
5860 return GDI_ERROR;
5863 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5865 ERR("called but we don't have FreeType\n");
5866 return 0;
5869 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5871 FIXME(":stub\n");
5872 return 1;
5875 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5877 FIXME(":stub\n");
5878 return TRUE;
5881 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5883 FIXME(":stub\n");
5884 return NULL;
5887 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5889 FIXME(":stub\n");
5890 return DEFAULT_CHARSET;
5893 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5895 return FALSE;
5898 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5900 FIXME("(%p, %p): stub\n", font, glyphset);
5901 return 0;
5904 BOOL WineEngFontIsLinked(GdiFont *font)
5906 return FALSE;
5909 /*************************************************************************
5910 * GetRasterizerCaps (GDI32.@)
5912 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5914 lprs->nSize = sizeof(RASTERIZER_STATUS);
5915 lprs->wFlags = 0;
5916 lprs->nLanguageID = 0;
5917 return TRUE;
5920 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5922 ERR("called but we don't have FreeType\n");
5923 return 0;
5926 #endif /* HAVE_FREETYPE */