push 283761c2088bbce3f1b27f01dcb83707e81913bc
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob7400b1257c5b7e1c289eb2bb483d618d61c4f44d
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
200 #undef MAKE_FUNCPTR
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
227 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229 FT_Short height;
230 FT_Short width;
231 FT_Pos size;
232 FT_Pos x_ppem;
233 FT_Pos y_ppem;
234 FT_Short internal_leading;
235 } Bitmap_Size;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
240 typedef struct {
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
245 struct enum_data
247 ENUMLOGFONTEXW elf;
248 NEWTEXTMETRICEXW ntm;
249 DWORD type;
252 typedef struct tagFace {
253 struct list entry;
254 WCHAR *StyleName;
255 char *file;
256 void *font_data_ptr;
257 DWORD font_data_size;
258 FT_Long face_index;
259 FONTSIGNATURE fs;
260 FONTSIGNATURE fs_links;
261 DWORD ntmFlags;
262 FT_Fixed font_version;
263 BOOL scalable;
264 Bitmap_Size size; /* set if face is a bitmap */
265 BOOL external; /* TRUE if we should manually add this font to the registry */
266 struct tagFamily *family;
267 /* Cached data for Enum */
268 struct enum_data *cached_enum_data;
269 } Face;
271 typedef struct tagFamily {
272 struct list entry;
273 const WCHAR *FamilyName;
274 struct list faces;
275 } Family;
277 typedef struct {
278 GLYPHMETRICS gm;
279 INT adv; /* These three hold to widths of the unrotated chars */
280 INT lsb;
281 INT bbx;
282 BOOL init;
283 } GM;
285 typedef struct {
286 FLOAT eM11, eM12;
287 FLOAT eM21, eM22;
288 } FMAT2;
290 typedef struct {
291 DWORD hash;
292 LOGFONTW lf;
293 FMAT2 matrix;
294 BOOL can_use_bitmap;
295 } FONT_DESC;
297 typedef struct tagHFONTLIST {
298 struct list entry;
299 HFONT hfont;
300 } HFONTLIST;
302 typedef struct {
303 struct list entry;
304 Face *face;
305 GdiFont *font;
306 } CHILD_FONT;
308 struct tagGdiFont {
309 struct list entry;
310 GM **gm;
311 DWORD gmsize;
312 struct list hfontlist;
313 OUTLINETEXTMETRICW *potm;
314 DWORD total_kern_pairs;
315 KERNINGPAIR *kern_pairs;
316 struct list child_fonts;
318 /* the following members can be accessed without locking, they are never modified after creation */
319 FT_Face ft_face;
320 struct font_mapping *mapping;
321 LPWSTR name;
322 int charset;
323 int codepage;
324 BOOL fake_italic;
325 BOOL fake_bold;
326 BYTE underline;
327 BYTE strikeout;
328 INT orientation;
329 FONT_DESC font_desc;
330 LONG aveWidth, ppem;
331 float scale_y;
332 SHORT yMax;
333 SHORT yMin;
334 DWORD ntmFlags;
335 FONTSIGNATURE fs;
336 GdiFont *base_font;
337 VOID *GSUB_Table;
340 typedef struct {
341 struct list entry;
342 const WCHAR *font_name;
343 struct list links;
344 } SYSTEM_LINKS;
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
350 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list = LIST_INIT(child_font_list);
353 static struct list system_links = LIST_INIT(system_links);
355 static struct list font_subst_list = LIST_INIT(font_subst_list);
357 static struct list font_list = LIST_INIT(font_list);
359 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
365 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
366 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372 'W','i','n','d','o','w','s',' ','N','T','\\',
373 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374 'F','o','n','t','s','\0'};
376 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
377 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
378 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
379 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
381 static const WCHAR * const SystemFontValues[4] = {
382 System_Value,
383 OEMFont_Value,
384 FixedSys_Value,
385 NULL
388 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
389 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
391 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
392 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
393 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
394 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
395 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
396 'E','u','r','o','p','e','a','n','\0'};
397 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
398 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
399 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
400 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
401 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
402 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
403 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
404 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
405 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
406 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
407 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
408 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
410 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
411 WesternW, /*00*/
412 Central_EuropeanW,
413 CyrillicW,
414 GreekW,
415 TurkishW,
416 HebrewW,
417 ArabicW,
418 BalticW,
419 VietnameseW, /*08*/
420 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
421 ThaiW,
422 JapaneseW,
423 CHINESE_GB2312W,
424 HangulW,
425 CHINESE_BIG5W,
426 Hangul_Johab_W,
427 NULL, NULL, /*23*/
428 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
429 SymbolW /*31*/
432 typedef struct {
433 WCHAR *name;
434 INT charset;
435 } NameCs;
437 typedef struct tagFontSubst {
438 struct list entry;
439 NameCs from;
440 NameCs to;
441 } FontSubst;
443 struct font_mapping
445 struct list entry;
446 int refcount;
447 dev_t dev;
448 ino_t ino;
449 void *data;
450 size_t size;
453 static struct list mappings_list = LIST_INIT( mappings_list );
455 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
457 static CRITICAL_SECTION freetype_cs;
458 static CRITICAL_SECTION_DEBUG critsect_debug =
460 0, 0, &freetype_cs,
461 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
462 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
464 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
466 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
468 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
469 static BOOL use_default_fallback = FALSE;
471 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
473 /****************************************
474 * Notes on .fon files
476 * The fonts System, FixedSys and Terminal are special. There are typically multiple
477 * versions installed for different resolutions and codepages. Windows stores which one to use
478 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
479 * Key Meaning
480 * FIXEDFON.FON FixedSys
481 * FONTS.FON System
482 * OEMFONT.FON Terminal
483 * LogPixels Current dpi set by the display control panel applet
484 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
485 * also has a LogPixels value that appears to mirror this)
487 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
488 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
489 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
490 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
491 * so that makes sense.
493 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
494 * to be mapped into the registry on Windows 2000 at least).
495 * I have
496 * woafont=app850.fon
497 * ega80woa.fon=ega80850.fon
498 * ega40woa.fon=ega40850.fon
499 * cga80woa.fon=cga80850.fon
500 * cga40woa.fon=cga40850.fon
503 /* These are all structures needed for the GSUB table */
505 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
506 #define TATEGAKI_LOWER_BOUND 0x02F1
508 typedef struct {
509 DWORD version;
510 WORD ScriptList;
511 WORD FeatureList;
512 WORD LookupList;
513 } GSUB_Header;
515 typedef struct {
516 CHAR ScriptTag[4];
517 WORD Script;
518 } GSUB_ScriptRecord;
520 typedef struct {
521 WORD ScriptCount;
522 GSUB_ScriptRecord ScriptRecord[1];
523 } GSUB_ScriptList;
525 typedef struct {
526 CHAR LangSysTag[4];
527 WORD LangSys;
528 } GSUB_LangSysRecord;
530 typedef struct {
531 WORD DefaultLangSys;
532 WORD LangSysCount;
533 GSUB_LangSysRecord LangSysRecord[1];
534 } GSUB_Script;
536 typedef struct {
537 WORD LookupOrder; /* Reserved */
538 WORD ReqFeatureIndex;
539 WORD FeatureCount;
540 WORD FeatureIndex[1];
541 } GSUB_LangSys;
543 typedef struct {
544 CHAR FeatureTag[4];
545 WORD Feature;
546 } GSUB_FeatureRecord;
548 typedef struct {
549 WORD FeatureCount;
550 GSUB_FeatureRecord FeatureRecord[1];
551 } GSUB_FeatureList;
553 typedef struct {
554 WORD FeatureParams; /* Reserved */
555 WORD LookupCount;
556 WORD LookupListIndex[1];
557 } GSUB_Feature;
559 typedef struct {
560 WORD LookupCount;
561 WORD Lookup[1];
562 } GSUB_LookupList;
564 typedef struct {
565 WORD LookupType;
566 WORD LookupFlag;
567 WORD SubTableCount;
568 WORD SubTable[1];
569 } GSUB_LookupTable;
571 typedef struct {
572 WORD CoverageFormat;
573 WORD GlyphCount;
574 WORD GlyphArray[1];
575 } GSUB_CoverageFormat1;
577 typedef struct {
578 WORD Start;
579 WORD End;
580 WORD StartCoverageIndex;
581 } GSUB_RangeRecord;
583 typedef struct {
584 WORD CoverageFormat;
585 WORD RangeCount;
586 GSUB_RangeRecord RangeRecord[1];
587 } GSUB_CoverageFormat2;
589 typedef struct {
590 WORD SubstFormat; /* = 1 */
591 WORD Coverage;
592 WORD DeltaGlyphID;
593 } GSUB_SingleSubstFormat1;
595 typedef struct {
596 WORD SubstFormat; /* = 2 */
597 WORD Coverage;
598 WORD GlyphCount;
599 WORD Substitute[1];
600 }GSUB_SingleSubstFormat2;
602 #ifdef HAVE_CARBON_CARBON_H
603 static char *find_cache_dir(void)
605 FSRef ref;
606 OSErr err;
607 static char cached_path[MAX_PATH];
608 static const char *wine = "/Wine", *fonts = "/Fonts";
610 if(*cached_path) return cached_path;
612 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
613 if(err != noErr)
615 WARN("can't create cached data folder\n");
616 return NULL;
618 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
619 if(err != noErr)
621 WARN("can't create cached data path\n");
622 *cached_path = '\0';
623 return NULL;
625 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
627 ERR("Could not create full path\n");
628 *cached_path = '\0';
629 return NULL;
631 strcat(cached_path, wine);
633 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
635 WARN("Couldn't mkdir %s\n", cached_path);
636 *cached_path = '\0';
637 return NULL;
639 strcat(cached_path, fonts);
640 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
642 WARN("Couldn't mkdir %s\n", cached_path);
643 *cached_path = '\0';
644 return NULL;
646 return cached_path;
649 /******************************************************************
650 * expand_mac_font
652 * Extracts individual TrueType font files from a Mac suitcase font
653 * and saves them into the user's caches directory (see
654 * find_cache_dir()).
655 * Returns a NULL terminated array of filenames.
657 * We do this because they are apps that try to read ttf files
658 * themselves and they don't like Mac suitcase files.
660 static char **expand_mac_font(const char *path)
662 FSRef ref;
663 SInt16 res_ref;
664 OSStatus s;
665 unsigned int idx;
666 const char *out_dir;
667 const char *filename;
668 int output_len;
669 struct {
670 char **array;
671 unsigned int size, max_size;
672 } ret;
674 TRACE("path %s\n", path);
676 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
677 if(s != noErr)
679 WARN("failed to get ref\n");
680 return NULL;
683 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
684 if(s != noErr)
686 TRACE("no data fork, so trying resource fork\n");
687 res_ref = FSOpenResFile(&ref, fsRdPerm);
688 if(res_ref == -1)
690 TRACE("unable to open resource fork\n");
691 return NULL;
695 ret.size = 0;
696 ret.max_size = 10;
697 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
698 if(!ret.array)
700 CloseResFile(res_ref);
701 return NULL;
704 out_dir = find_cache_dir();
706 filename = strrchr(path, '/');
707 if(!filename) filename = path;
708 else filename++;
710 /* output filename has the form out_dir/filename_%04x.ttf */
711 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
713 UseResFile(res_ref);
714 idx = 1;
715 while(1)
717 FamRec *fam_rec;
718 unsigned short *num_faces_ptr, num_faces, face;
719 AsscEntry *assoc;
720 Handle fond;
721 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
723 fond = Get1IndResource(fond_res, idx);
724 if(!fond) break;
725 TRACE("got fond resource %d\n", idx);
726 HLock(fond);
728 fam_rec = *(FamRec**)fond;
729 num_faces_ptr = (unsigned short *)(fam_rec + 1);
730 num_faces = GET_BE_WORD(*num_faces_ptr);
731 num_faces++;
732 assoc = (AsscEntry*)(num_faces_ptr + 1);
733 TRACE("num faces %04x\n", num_faces);
734 for(face = 0; face < num_faces; face++, assoc++)
736 Handle sfnt;
737 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
738 unsigned short size, font_id;
739 char *output;
741 size = GET_BE_WORD(assoc->fontSize);
742 font_id = GET_BE_WORD(assoc->fontID);
743 if(size != 0)
745 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
746 continue;
749 TRACE("trying to load sfnt id %04x\n", font_id);
750 sfnt = GetResource(sfnt_res, font_id);
751 if(!sfnt)
753 TRACE("can't get sfnt resource %04x\n", font_id);
754 continue;
757 output = HeapAlloc(GetProcessHeap(), 0, output_len);
758 if(output)
760 int fd;
762 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
764 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
765 if(fd != -1 || errno == EEXIST)
767 if(fd != -1)
769 unsigned char *sfnt_data;
771 HLock(sfnt);
772 sfnt_data = *(unsigned char**)sfnt;
773 write(fd, sfnt_data, GetHandleSize(sfnt));
774 HUnlock(sfnt);
775 close(fd);
777 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
779 ret.max_size *= 2;
780 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
782 ret.array[ret.size++] = output;
784 else
786 WARN("unable to create %s\n", output);
787 HeapFree(GetProcessHeap(), 0, output);
790 ReleaseResource(sfnt);
792 HUnlock(fond);
793 ReleaseResource(fond);
794 idx++;
796 CloseResFile(res_ref);
798 return ret.array;
801 #endif /* HAVE_CARBON_CARBON_H */
803 static inline BOOL is_win9x(void)
805 return GetVersion() & 0x80000000;
808 This function builds an FT_Fixed from a float. It puts the integer part
809 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
810 It fails if the integer part of the float number is greater than SHORT_MAX.
812 static inline FT_Fixed FT_FixedFromFloat(float f)
814 short value = f;
815 unsigned short fract = (f - value) * 0xFFFF;
816 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
825 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
829 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
831 Family *family;
832 Face *face;
833 const char *file;
834 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
835 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
837 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
840 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
842 if(face_name && strcmpiW(face_name, family->FamilyName))
843 continue;
844 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
846 if (!face->file)
847 continue;
848 file = strrchr(face->file, '/');
849 if(!file)
850 file = face->file;
851 else
852 file++;
853 if(!strcasecmp(file, file_nameA))
855 HeapFree(GetProcessHeap(), 0, file_nameA);
856 return face;
860 HeapFree(GetProcessHeap(), 0, file_nameA);
861 return NULL;
864 static Family *find_family_from_name(const WCHAR *name)
866 Family *family;
868 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
870 if(!strcmpiW(family->FamilyName, name))
871 return family;
874 return NULL;
877 static void DumpSubstList(void)
879 FontSubst *psub;
881 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
883 if(psub->from.charset != -1 || psub->to.charset != -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
885 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
886 else
887 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
888 debugstr_w(psub->to.name));
890 return;
893 static LPWSTR strdupW(LPCWSTR p)
895 LPWSTR ret;
896 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
897 ret = HeapAlloc(GetProcessHeap(), 0, len);
898 memcpy(ret, p, len);
899 return ret;
902 static LPSTR strdupA(LPCSTR p)
904 LPSTR ret;
905 DWORD len = (strlen(p) + 1);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
907 memcpy(ret, p, len);
908 return ret;
911 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
912 INT from_charset)
914 FontSubst *element;
916 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
918 if(!strcmpiW(element->from.name, from_name) &&
919 (element->from.charset == from_charset ||
920 element->from.charset == -1))
921 return element;
924 return NULL;
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
931 FontSubst *from_exist, *to_exist;
933 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
935 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
937 list_remove(&from_exist->entry);
938 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
939 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
940 HeapFree(GetProcessHeap(), 0, from_exist);
941 from_exist = NULL;
944 if(!from_exist)
946 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
948 if(to_exist)
950 HeapFree(GetProcessHeap(), 0, subst->to.name);
951 subst->to.name = strdupW(to_exist->to.name);
954 list_add_tail(subst_list, &subst->entry);
956 return TRUE;
959 HeapFree(GetProcessHeap(), 0, subst->from.name);
960 HeapFree(GetProcessHeap(), 0, subst->to.name);
961 HeapFree(GetProcessHeap(), 0, subst);
962 return FALSE;
965 static void split_subst_info(NameCs *nc, LPSTR str)
967 CHAR *p = strrchr(str, ',');
968 DWORD len;
970 nc->charset = -1;
971 if(p && *(p+1)) {
972 nc->charset = strtol(p+1, NULL, 10);
973 *p = '\0';
975 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
976 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
980 static void LoadSubstList(void)
982 FontSubst *psub;
983 HKEY hkey;
984 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
985 LPSTR value;
986 LPVOID data;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey) == ERROR_SUCCESS) {
992 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 &valuelen, &datalen, NULL, NULL);
995 valuelen++; /* returned value doesn't include room for '\0' */
996 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
997 data = HeapAlloc(GetProcessHeap(), 0, datalen);
999 dlen = datalen;
1000 vlen = valuelen;
1001 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1002 &dlen) == ERROR_SUCCESS) {
1003 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1005 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1006 split_subst_info(&psub->from, value);
1007 split_subst_info(&psub->to, data);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if((psub->to.charset != psub->from.charset) ||
1012 psub->to.charset == DEFAULT_CHARSET) {
1013 HeapFree(GetProcessHeap(), 0, psub->to.name);
1014 HeapFree(GetProcessHeap(), 0, psub->from.name);
1015 HeapFree(GetProcessHeap(), 0, psub);
1016 } else {
1017 add_font_subst(&font_subst_list, psub, 0);
1019 /* reset dlen and vlen */
1020 dlen = datalen;
1021 vlen = valuelen;
1023 HeapFree(GetProcessHeap(), 0, data);
1024 HeapFree(GetProcessHeap(), 0, value);
1025 RegCloseKey(hkey);
1029 static WCHAR *get_familyname(FT_Face ft_face)
1031 WCHAR *family = NULL;
1032 FT_SfntName name;
1033 FT_UInt num_names, name_index, i;
1035 if(FT_IS_SFNT(ft_face))
1037 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1039 for(name_index = 0; name_index < num_names; name_index++)
1041 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1043 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1044 (name.language_id == GetUserDefaultLCID()) &&
1045 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1046 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1048 /* String is not nul terminated and string_len is a byte length. */
1049 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1050 for(i = 0; i < name.string_len / 2; i++)
1052 WORD *tmp = (WORD *)&name.string[i * 2];
1053 family[i] = GET_BE_WORD(*tmp);
1055 family[i] = 0;
1057 TRACE("Got localised name %s\n", debugstr_w(family));
1058 return family;
1064 return NULL;
1068 /*****************************************************************
1069 * load_sfnt_table
1071 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1072 * of FreeType that don't export this function.
1075 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1078 FT_Error err;
1080 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1081 if(pFT_Load_Sfnt_Table)
1083 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1085 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1086 else /* Do it the hard way */
1088 TT_Face tt_face = (TT_Face) ft_face;
1089 SFNT_Interface *sfnt;
1090 if (FT_Version.major==2 && FT_Version.minor==0)
1092 /* 2.0.x */
1093 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1095 else
1097 /* A field was added in the middle of the structure in 2.1.x */
1098 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1100 err = sfnt->load_any(tt_face, table, offset, buf, len);
1102 #else
1103 else
1105 static int msg;
1106 if(!msg)
1108 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1109 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1110 "Please upgrade your freetype library.\n");
1111 msg++;
1113 err = FT_Err_Unimplemented_Feature;
1115 #endif
1116 return err;
1119 static inline int TestStyles(DWORD flags, DWORD styles)
1121 return (flags & styles) == styles;
1124 static int StyleOrdering(Face *face)
1126 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1127 return 3;
1128 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1129 return 2;
1130 if (TestStyles(face->ntmFlags, NTM_BOLD))
1131 return 1;
1132 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1133 return 0;
1135 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1136 debugstr_w(face->family->FamilyName),
1137 debugstr_w(face->StyleName),
1138 face->ntmFlags);
1140 return 9999;
1143 /* Add a style of face to a font family using an ordering of the list such
1144 that regular fonts come before bold and italic, and single styles come
1145 before compound styles. */
1146 static void AddFaceToFamily(Face *face, Family *family)
1148 struct list *entry;
1150 LIST_FOR_EACH( entry, &family->faces )
1152 Face *ent = LIST_ENTRY(entry, Face, entry);
1153 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1155 list_add_before( entry, &face->entry );
1158 #define ADDFONT_EXTERNAL_FONT 0x01
1159 #define ADDFONT_FORCE_BITMAP 0x02
1160 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1162 FT_Face ft_face;
1163 TT_OS2 *pOS2;
1164 TT_Header *pHeader = NULL;
1165 WCHAR *english_family, *localised_family, *StyleW;
1166 DWORD len;
1167 Family *family;
1168 Face *face;
1169 struct list *family_elem_ptr, *face_elem_ptr;
1170 FT_Error err;
1171 FT_Long face_index = 0, num_faces;
1172 #ifdef HAVE_FREETYPE_FTWINFNT_H
1173 FT_WinFNT_HeaderRec winfnt_header;
1174 #endif
1175 int i, bitmap_num, internal_leading;
1176 FONTSIGNATURE fs;
1178 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1179 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1181 #ifdef HAVE_CARBON_CARBON_H
1182 if(file && !fake_family)
1184 char **mac_list = expand_mac_font(file);
1185 if(mac_list)
1187 BOOL had_one = FALSE;
1188 char **cursor;
1189 for(cursor = mac_list; *cursor; cursor++)
1191 had_one = TRUE;
1192 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1193 HeapFree(GetProcessHeap(), 0, *cursor);
1195 HeapFree(GetProcessHeap(), 0, mac_list);
1196 if(had_one)
1197 return 1;
1200 #endif /* HAVE_CARBON_CARBON_H */
1202 do {
1203 char *family_name = fake_family;
1205 if (file)
1207 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1208 err = pFT_New_Face(library, file, face_index, &ft_face);
1209 } else
1211 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1212 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1215 if(err != 0) {
1216 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1217 return 0;
1220 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*/
1221 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1222 pFT_Done_Face(ft_face);
1223 return 0;
1226 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1227 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1228 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1229 pFT_Done_Face(ft_face);
1230 return 0;
1233 if(FT_IS_SFNT(ft_face))
1235 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1236 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1237 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1239 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1240 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1241 pFT_Done_Face(ft_face);
1242 return 0;
1245 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1246 we don't want to load these. */
1247 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1249 FT_ULong len = 0;
1251 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1253 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1254 pFT_Done_Face(ft_face);
1255 return 0;
1260 if(!ft_face->family_name || !ft_face->style_name) {
1261 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1262 pFT_Done_Face(ft_face);
1263 return 0;
1266 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1268 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1269 pFT_Done_Face(ft_face);
1270 return 0;
1273 if (target_family)
1275 localised_family = get_familyname(ft_face);
1276 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1278 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1279 HeapFree(GetProcessHeap(), 0, localised_family);
1280 num_faces = ft_face->num_faces;
1281 pFT_Done_Face(ft_face);
1282 continue;
1284 HeapFree(GetProcessHeap(), 0, localised_family);
1287 if(!family_name)
1288 family_name = ft_face->family_name;
1290 bitmap_num = 0;
1291 do {
1292 My_FT_Bitmap_Size *size = NULL;
1293 FT_ULong tmp_size;
1295 if(!FT_IS_SCALABLE(ft_face))
1296 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1298 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1299 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1300 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1302 localised_family = NULL;
1303 if(!fake_family) {
1304 localised_family = get_familyname(ft_face);
1305 if(localised_family && !strcmpW(localised_family, english_family)) {
1306 HeapFree(GetProcessHeap(), 0, localised_family);
1307 localised_family = NULL;
1311 family = NULL;
1312 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1313 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1314 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1315 break;
1316 family = NULL;
1318 if(!family) {
1319 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1320 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1321 list_init(&family->faces);
1322 list_add_tail(&font_list, &family->entry);
1324 if(localised_family) {
1325 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1326 subst->from.name = strdupW(english_family);
1327 subst->from.charset = -1;
1328 subst->to.name = strdupW(localised_family);
1329 subst->to.charset = -1;
1330 add_font_subst(&font_subst_list, subst, 0);
1333 HeapFree(GetProcessHeap(), 0, localised_family);
1334 HeapFree(GetProcessHeap(), 0, english_family);
1336 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1337 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1338 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1340 internal_leading = 0;
1341 memset(&fs, 0, sizeof(fs));
1343 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1344 if(pOS2) {
1345 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1346 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1347 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1348 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1349 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1350 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1351 if(pOS2->version == 0) {
1352 FT_UInt dummy;
1354 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1355 fs.fsCsb[0] |= FS_LATIN1;
1356 else
1357 fs.fsCsb[0] |= FS_SYMBOL;
1360 #ifdef HAVE_FREETYPE_FTWINFNT_H
1361 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1362 CHARSETINFO csi;
1363 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1364 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1365 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1366 fs = csi.fs;
1367 internal_leading = winfnt_header.internal_leading;
1369 #endif
1371 face_elem_ptr = list_head(&family->faces);
1372 while(face_elem_ptr) {
1373 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1374 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1375 if(!strcmpW(face->StyleName, StyleW) &&
1376 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1377 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1378 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1379 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1381 if(fake_family) {
1382 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1383 HeapFree(GetProcessHeap(), 0, StyleW);
1384 pFT_Done_Face(ft_face);
1385 return 1;
1387 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1388 TRACE("Original font is newer so skipping this one\n");
1389 HeapFree(GetProcessHeap(), 0, StyleW);
1390 pFT_Done_Face(ft_face);
1391 return 1;
1392 } else {
1393 TRACE("Replacing original with this one\n");
1394 list_remove(&face->entry);
1395 HeapFree(GetProcessHeap(), 0, face->file);
1396 HeapFree(GetProcessHeap(), 0, face->StyleName);
1397 HeapFree(GetProcessHeap(), 0, face);
1398 break;
1402 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1403 face->cached_enum_data = NULL;
1404 face->StyleName = StyleW;
1405 if (file)
1407 face->file = strdupA(file);
1408 face->font_data_ptr = NULL;
1409 face->font_data_size = 0;
1411 else
1413 face->file = NULL;
1414 face->font_data_ptr = font_data_ptr;
1415 face->font_data_size = font_data_size;
1417 face->face_index = face_index;
1418 face->ntmFlags = 0;
1419 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1420 face->ntmFlags |= NTM_ITALIC;
1421 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1422 face->ntmFlags |= NTM_BOLD;
1423 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1424 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1425 face->family = family;
1426 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1427 face->fs = fs;
1428 memset(&face->fs_links, 0, sizeof(face->fs_links));
1430 if(FT_IS_SCALABLE(ft_face)) {
1431 memset(&face->size, 0, sizeof(face->size));
1432 face->scalable = TRUE;
1433 } else {
1434 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1435 size->height, size->width, size->size >> 6,
1436 size->x_ppem >> 6, size->y_ppem >> 6);
1437 face->size.height = size->height;
1438 face->size.width = size->width;
1439 face->size.size = size->size;
1440 face->size.x_ppem = size->x_ppem;
1441 face->size.y_ppem = size->y_ppem;
1442 face->size.internal_leading = internal_leading;
1443 face->scalable = FALSE;
1446 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1447 tmp_size = 0;
1448 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1450 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1451 face->ntmFlags |= NTM_PS_OPENTYPE;
1454 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1455 face->fs.fsCsb[0], face->fs.fsCsb[1],
1456 face->fs.fsUsb[0], face->fs.fsUsb[1],
1457 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1460 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1461 for(i = 0; i < ft_face->num_charmaps; i++) {
1462 switch(ft_face->charmaps[i]->encoding) {
1463 case FT_ENCODING_UNICODE:
1464 case FT_ENCODING_APPLE_ROMAN:
1465 face->fs.fsCsb[0] |= FS_LATIN1;
1466 break;
1467 case FT_ENCODING_MS_SYMBOL:
1468 face->fs.fsCsb[0] |= FS_SYMBOL;
1469 break;
1470 default:
1471 break;
1476 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1477 have_installed_roman_font = TRUE;
1479 AddFaceToFamily(face, family);
1481 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1483 num_faces = ft_face->num_faces;
1484 pFT_Done_Face(ft_face);
1485 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1486 debugstr_w(StyleW));
1487 } while(num_faces > ++face_index);
1488 return num_faces;
1491 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1493 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1496 static void DumpFontList(void)
1498 Family *family;
1499 Face *face;
1500 struct list *family_elem_ptr, *face_elem_ptr;
1502 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1503 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1504 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1505 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1506 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1507 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1508 if(!face->scalable)
1509 TRACE(" %d", face->size.height);
1510 TRACE("\n");
1513 return;
1516 /***********************************************************
1517 * The replacement list is a way to map an entire font
1518 * family onto another family. For example adding
1520 * [HKCU\Software\Wine\Fonts\Replacements]
1521 * "Wingdings"="Winedings"
1523 * would enumerate the Winedings font both as Winedings and
1524 * Wingdings. However if a real Wingdings font is present the
1525 * replacement does not take place.
1528 static void LoadReplaceList(void)
1530 HKEY hkey;
1531 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1532 LPWSTR value;
1533 LPVOID data;
1534 Family *family;
1535 Face *face;
1536 struct list *family_elem_ptr, *face_elem_ptr;
1537 CHAR familyA[400];
1539 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1540 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1542 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1543 &valuelen, &datalen, NULL, NULL);
1545 valuelen++; /* returned value doesn't include room for '\0' */
1546 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1547 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1549 dlen = datalen;
1550 vlen = valuelen;
1551 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1552 &dlen) == ERROR_SUCCESS) {
1553 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1554 /* "NewName"="Oldname" */
1555 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1557 /* Find the old family and hence all of the font files
1558 in that family */
1559 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1560 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1561 if(!strcmpiW(family->FamilyName, data)) {
1562 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1563 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1564 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1565 debugstr_w(face->StyleName), familyA);
1566 /* Now add a new entry with the new family name */
1567 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1569 break;
1572 /* reset dlen and vlen */
1573 dlen = datalen;
1574 vlen = valuelen;
1576 HeapFree(GetProcessHeap(), 0, data);
1577 HeapFree(GetProcessHeap(), 0, value);
1578 RegCloseKey(hkey);
1582 /*************************************************************
1583 * init_system_links
1585 static BOOL init_system_links(void)
1587 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1588 'W','i','n','d','o','w','s',' ','N','T','\\',
1589 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1590 'S','y','s','t','e','m','L','i','n','k',0};
1591 HKEY hkey;
1592 BOOL ret = FALSE;
1593 DWORD type, max_val, max_data, val_len, data_len, index;
1594 WCHAR *value, *data;
1595 WCHAR *entry, *next;
1596 SYSTEM_LINKS *font_link, *system_font_link;
1597 CHILD_FONT *child_font;
1598 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1599 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1600 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1601 FONTSIGNATURE fs;
1602 Family *family;
1603 Face *face;
1604 FontSubst *psub;
1606 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1608 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1609 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1610 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1611 val_len = max_val + 1;
1612 data_len = max_data;
1613 index = 0;
1614 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1616 TRACE("%s:\n", debugstr_w(value));
1618 memset(&fs, 0, sizeof(fs));
1619 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1620 psub = get_font_subst(&font_subst_list, value, -1);
1621 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1622 list_init(&font_link->links);
1623 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1625 WCHAR *face_name;
1626 CHILD_FONT *child_font;
1628 TRACE("\t%s\n", debugstr_w(entry));
1630 next = entry + strlenW(entry) + 1;
1632 face_name = strchrW(entry, ',');
1633 if(face_name)
1635 *face_name++ = 0;
1636 while(isspaceW(*face_name))
1637 face_name++;
1639 psub = get_font_subst(&font_subst_list, face_name, -1);
1640 if(psub)
1641 face_name = psub->to.name;
1643 face = find_face_from_filename(entry, face_name);
1644 if(!face)
1646 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1647 continue;
1650 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1651 child_font->face = face;
1652 child_font->font = NULL;
1653 fs.fsCsb[0] |= face->fs.fsCsb[0];
1654 fs.fsCsb[1] |= face->fs.fsCsb[1];
1655 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1656 list_add_tail(&font_link->links, &child_font->entry);
1658 family = find_family_from_name(font_link->font_name);
1659 if(family)
1661 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1663 face->fs_links = fs;
1666 list_add_tail(&system_links, &font_link->entry);
1667 val_len = max_val + 1;
1668 data_len = max_data;
1671 HeapFree(GetProcessHeap(), 0, value);
1672 HeapFree(GetProcessHeap(), 0, data);
1673 RegCloseKey(hkey);
1676 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1677 that Tahoma has */
1679 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1680 system_font_link->font_name = strdupW(System);
1681 list_init(&system_font_link->links);
1683 face = find_face_from_filename(tahoma_ttf, Tahoma);
1684 if(face)
1686 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1687 child_font->face = face;
1688 child_font->font = NULL;
1689 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1690 list_add_tail(&system_font_link->links, &child_font->entry);
1692 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1694 if(!strcmpiW(font_link->font_name, Tahoma))
1696 CHILD_FONT *font_link_entry;
1697 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1699 CHILD_FONT *new_child;
1700 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1701 new_child->face = font_link_entry->face;
1702 new_child->font = NULL;
1703 list_add_tail(&system_font_link->links, &new_child->entry);
1705 break;
1708 list_add_tail(&system_links, &system_font_link->entry);
1709 return ret;
1712 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1714 DIR *dir;
1715 struct dirent *dent;
1716 char path[MAX_PATH];
1718 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1720 dir = opendir(dirname);
1721 if(!dir) {
1722 WARN("Can't open directory %s\n", debugstr_a(dirname));
1723 return FALSE;
1725 while((dent = readdir(dir)) != NULL) {
1726 struct stat statbuf;
1728 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1729 continue;
1731 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1733 sprintf(path, "%s/%s", dirname, dent->d_name);
1735 if(stat(path, &statbuf) == -1)
1737 WARN("Can't stat %s\n", debugstr_a(path));
1738 continue;
1740 if(S_ISDIR(statbuf.st_mode))
1741 ReadFontDir(path, external_fonts);
1742 else
1743 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1745 closedir(dir);
1746 return TRUE;
1749 static void load_fontconfig_fonts(void)
1751 #ifdef SONAME_LIBFONTCONFIG
1752 void *fc_handle = NULL;
1753 FcConfig *config;
1754 FcPattern *pat;
1755 FcObjectSet *os;
1756 FcFontSet *fontset;
1757 int i, len;
1758 char *file;
1759 const char *ext;
1761 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1762 if(!fc_handle) {
1763 TRACE("Wine cannot find the fontconfig library (%s).\n",
1764 SONAME_LIBFONTCONFIG);
1765 return;
1767 #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;}
1768 LOAD_FUNCPTR(FcConfigGetCurrent);
1769 LOAD_FUNCPTR(FcFontList);
1770 LOAD_FUNCPTR(FcFontSetDestroy);
1771 LOAD_FUNCPTR(FcInit);
1772 LOAD_FUNCPTR(FcObjectSetAdd);
1773 LOAD_FUNCPTR(FcObjectSetCreate);
1774 LOAD_FUNCPTR(FcObjectSetDestroy);
1775 LOAD_FUNCPTR(FcPatternCreate);
1776 LOAD_FUNCPTR(FcPatternDestroy);
1777 LOAD_FUNCPTR(FcPatternGetBool);
1778 LOAD_FUNCPTR(FcPatternGetString);
1779 #undef LOAD_FUNCPTR
1781 if(!pFcInit()) return;
1783 config = pFcConfigGetCurrent();
1784 pat = pFcPatternCreate();
1785 os = pFcObjectSetCreate();
1786 pFcObjectSetAdd(os, FC_FILE);
1787 pFcObjectSetAdd(os, FC_SCALABLE);
1788 fontset = pFcFontList(config, pat, os);
1789 if(!fontset) return;
1790 for(i = 0; i < fontset->nfont; i++) {
1791 FcBool scalable;
1793 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1794 continue;
1795 TRACE("fontconfig: %s\n", file);
1797 /* We're just interested in OT/TT fonts for now, so this hack just
1798 picks up the scalable fonts without extensions .pf[ab] to save time
1799 loading every other font */
1801 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1803 TRACE("not scalable\n");
1804 continue;
1807 len = strlen( file );
1808 if(len < 4) continue;
1809 ext = &file[ len - 3 ];
1810 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1811 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1813 pFcFontSetDestroy(fontset);
1814 pFcObjectSetDestroy(os);
1815 pFcPatternDestroy(pat);
1816 sym_not_found:
1817 #endif
1818 return;
1821 static BOOL load_font_from_data_dir(LPCWSTR file)
1823 BOOL ret = FALSE;
1824 const char *data_dir = wine_get_data_dir();
1826 if (!data_dir) data_dir = wine_get_build_dir();
1828 if (data_dir)
1830 INT len;
1831 char *unix_name;
1833 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1835 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1837 strcpy(unix_name, data_dir);
1838 strcat(unix_name, "/fonts/");
1840 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1842 EnterCriticalSection( &freetype_cs );
1843 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1844 LeaveCriticalSection( &freetype_cs );
1845 HeapFree(GetProcessHeap(), 0, unix_name);
1847 return ret;
1850 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1852 static const WCHAR slashW[] = {'\\','\0'};
1853 BOOL ret = FALSE;
1854 WCHAR windowsdir[MAX_PATH];
1855 char *unixname;
1857 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1858 strcatW(windowsdir, fontsW);
1859 strcatW(windowsdir, slashW);
1860 strcatW(windowsdir, file);
1861 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1862 EnterCriticalSection( &freetype_cs );
1863 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1864 LeaveCriticalSection( &freetype_cs );
1865 HeapFree(GetProcessHeap(), 0, unixname);
1867 return ret;
1870 static void load_system_fonts(void)
1872 HKEY hkey;
1873 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1874 const WCHAR * const *value;
1875 DWORD dlen, type;
1876 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1877 char *unixname;
1879 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1880 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1881 strcatW(windowsdir, fontsW);
1882 for(value = SystemFontValues; *value; value++) {
1883 dlen = sizeof(data);
1884 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1885 type == REG_SZ) {
1886 BOOL added = FALSE;
1888 sprintfW(pathW, fmtW, windowsdir, data);
1889 if((unixname = wine_get_unix_file_name(pathW))) {
1890 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1891 HeapFree(GetProcessHeap(), 0, unixname);
1893 if (!added)
1894 load_font_from_data_dir(data);
1897 RegCloseKey(hkey);
1901 /*************************************************************
1903 * This adds registry entries for any externally loaded fonts
1904 * (fonts from fontconfig or FontDirs). It also deletes entries
1905 * of no longer existing fonts.
1908 static void update_reg_entries(void)
1910 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1911 LPWSTR valueW;
1912 DWORD len, len_fam;
1913 Family *family;
1914 Face *face;
1915 struct list *family_elem_ptr, *face_elem_ptr;
1916 WCHAR *file;
1917 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1918 static const WCHAR spaceW[] = {' ', '\0'};
1919 char *path;
1921 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1922 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1923 ERR("Can't create Windows font reg key\n");
1924 goto end;
1927 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1928 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1929 ERR("Can't create Windows font reg key\n");
1930 goto end;
1933 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1934 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1935 ERR("Can't create external font reg key\n");
1936 goto end;
1939 /* enumerate the fonts and add external ones to the two keys */
1941 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1942 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1943 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1944 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1945 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1946 if(!face->external) continue;
1947 len = len_fam;
1948 if(strcmpiW(face->StyleName, RegularW))
1949 len = len_fam + strlenW(face->StyleName) + 1;
1950 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1951 strcpyW(valueW, family->FamilyName);
1952 if(len != len_fam) {
1953 strcatW(valueW, spaceW);
1954 strcatW(valueW, face->StyleName);
1956 strcatW(valueW, TrueType);
1958 file = wine_get_dos_file_name(face->file);
1959 if(file)
1960 len = strlenW(file) + 1;
1961 else
1963 if((path = strrchr(face->file, '/')) == NULL)
1964 path = face->file;
1965 else
1966 path++;
1967 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1969 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1970 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1972 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1973 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1974 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1976 HeapFree(GetProcessHeap(), 0, file);
1977 HeapFree(GetProcessHeap(), 0, valueW);
1980 end:
1981 if(external_key) RegCloseKey(external_key);
1982 if(win9x_key) RegCloseKey(win9x_key);
1983 if(winnt_key) RegCloseKey(winnt_key);
1984 return;
1987 static void delete_external_font_keys(void)
1989 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1990 DWORD dlen, vlen, datalen, valuelen, i, type;
1991 LPWSTR valueW;
1992 LPVOID data;
1994 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1995 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1996 ERR("Can't create Windows font reg key\n");
1997 goto end;
2000 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2001 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2002 ERR("Can't create Windows font reg key\n");
2003 goto end;
2006 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2007 ERR("Can't create external font reg key\n");
2008 goto end;
2011 /* Delete all external fonts added last time */
2013 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2014 &valuelen, &datalen, NULL, NULL);
2015 valuelen++; /* returned value doesn't include room for '\0' */
2016 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2017 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2019 dlen = datalen * sizeof(WCHAR);
2020 vlen = valuelen;
2021 i = 0;
2022 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2023 &dlen) == ERROR_SUCCESS) {
2025 RegDeleteValueW(winnt_key, valueW);
2026 RegDeleteValueW(win9x_key, valueW);
2027 /* reset dlen and vlen */
2028 dlen = datalen;
2029 vlen = valuelen;
2031 HeapFree(GetProcessHeap(), 0, data);
2032 HeapFree(GetProcessHeap(), 0, valueW);
2034 /* Delete the old external fonts key */
2035 RegCloseKey(external_key);
2036 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2038 end:
2039 if(win9x_key) RegCloseKey(win9x_key);
2040 if(winnt_key) RegCloseKey(winnt_key);
2043 /*************************************************************
2044 * WineEngAddFontResourceEx
2047 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2049 INT ret = 0;
2050 if (ft_handle) /* do it only if we have freetype up and running */
2052 char *unixname;
2054 if(flags)
2055 FIXME("Ignoring flags %x\n", flags);
2057 if((unixname = wine_get_unix_file_name(file)))
2059 EnterCriticalSection( &freetype_cs );
2060 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2061 LeaveCriticalSection( &freetype_cs );
2062 HeapFree(GetProcessHeap(), 0, unixname);
2064 if (!ret && !strchrW(file, '\\')) {
2065 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2066 ret = load_font_from_winfonts_dir(file);
2067 if (!ret) {
2068 /* Try in datadir/fonts (or builddir/fonts),
2069 * needed for Magic the Gathering Online
2071 ret = load_font_from_data_dir(file);
2075 return ret;
2078 /*************************************************************
2079 * WineEngAddFontMemResourceEx
2082 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2084 if (ft_handle) /* do it only if we have freetype up and running */
2086 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2088 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2089 memcpy(pFontCopy, pbFont, cbFont);
2091 EnterCriticalSection( &freetype_cs );
2092 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2093 LeaveCriticalSection( &freetype_cs );
2095 if (*pcFonts == 0)
2097 TRACE("AddFontToList failed\n");
2098 HeapFree(GetProcessHeap(), 0, pFontCopy);
2099 return NULL;
2101 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2102 * For now return something unique but quite random
2104 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2105 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2108 *pcFonts = 0;
2109 return 0;
2112 /*************************************************************
2113 * WineEngRemoveFontResourceEx
2116 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2118 FIXME(":stub\n");
2119 return TRUE;
2122 static const struct nls_update_font_list
2124 UINT ansi_cp, oem_cp;
2125 const char *oem, *fixed, *system;
2126 const char *courier, *serif, *small, *sserif;
2127 /* these are for font substitute */
2128 const char *shelldlg, *tmsrmn;
2129 } nls_update_font_list[] =
2131 /* Latin 1 (United States) */
2132 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2133 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2134 "Tahoma","Times New Roman",
2136 /* Latin 1 (Multilingual) */
2137 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2138 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2139 "Tahoma","Times New Roman", /* FIXME unverified */
2141 /* Eastern Europe */
2142 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2143 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2144 "Tahoma","Times New Roman", /* FIXME unverified */
2146 /* Cyrillic */
2147 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2148 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2149 "Tahoma","Times New Roman", /* FIXME unverified */
2151 /* Greek */
2152 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2153 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2154 "Tahoma","Times New Roman", /* FIXME unverified */
2156 /* Turkish */
2157 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2158 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2159 "Tahoma","Times New Roman", /* FIXME unverified */
2161 /* Hebrew */
2162 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2163 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2164 "Tahoma","Times New Roman", /* FIXME unverified */
2166 /* Arabic */
2167 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2168 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2169 "Tahoma","Times New Roman", /* FIXME unverified */
2171 /* Baltic */
2172 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2173 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2174 "Tahoma","Times New Roman", /* FIXME unverified */
2176 /* Vietnamese */
2177 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2178 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2179 "Tahoma","Times New Roman", /* FIXME unverified */
2181 /* Thai */
2182 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2183 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2184 "Tahoma","Times New Roman", /* FIXME unverified */
2186 /* Japanese */
2187 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2188 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2189 "MS UI Gothic","MS Serif",
2191 /* Chinese Simplified */
2192 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2193 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2194 "Tahoma", "Times New Roman", /* FIXME unverified */
2196 /* Korean */
2197 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2198 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2199 "Gulim", "Batang",
2201 /* Chinese Traditional */
2202 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2203 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2204 "PMingLiU", "MingLiU",
2208 static inline HKEY create_fonts_NT_registry_key(void)
2210 HKEY hkey = 0;
2212 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2213 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2214 return hkey;
2217 static inline HKEY create_fonts_9x_registry_key(void)
2219 HKEY hkey = 0;
2221 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2222 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2223 return hkey;
2226 static inline HKEY create_config_fonts_registry_key(void)
2228 HKEY hkey = 0;
2230 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2231 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2232 return hkey;
2235 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2237 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2238 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2239 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2240 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2243 static void update_font_info(void)
2245 char buf[40], cpbuf[40];
2246 DWORD len, type;
2247 HKEY hkey = 0;
2248 UINT i, ansi_cp = 0, oem_cp = 0;
2250 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2251 return;
2253 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2254 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2255 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2256 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2257 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2259 /* Setup Default_Fallback usage */
2260 if (ansi_cp == 932)
2261 use_default_fallback = TRUE;
2263 len = sizeof(buf);
2264 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2266 if (!strcmp( buf, cpbuf )) /* already set correctly */
2268 RegCloseKey(hkey);
2269 return;
2271 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2273 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2275 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2276 RegCloseKey(hkey);
2278 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2280 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2281 nls_update_font_list[i].oem_cp == oem_cp)
2283 HKEY hkey;
2285 hkey = create_config_fonts_registry_key();
2286 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2287 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2288 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2289 RegCloseKey(hkey);
2291 hkey = create_fonts_NT_registry_key();
2292 add_font_list(hkey, &nls_update_font_list[i]);
2293 RegCloseKey(hkey);
2295 hkey = create_fonts_9x_registry_key();
2296 add_font_list(hkey, &nls_update_font_list[i]);
2297 RegCloseKey(hkey);
2299 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2301 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2302 strlen(nls_update_font_list[i].shelldlg)+1);
2303 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2304 strlen(nls_update_font_list[i].tmsrmn)+1);
2305 RegCloseKey(hkey);
2307 return;
2310 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2314 static BOOL init_freetype(void)
2316 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2317 if(!ft_handle) {
2318 WINE_MESSAGE(
2319 "Wine cannot find the FreeType font library. To enable Wine to\n"
2320 "use TrueType fonts please install a version of FreeType greater than\n"
2321 "or equal to 2.0.5.\n"
2322 "http://www.freetype.org\n");
2323 return FALSE;
2326 #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;}
2328 LOAD_FUNCPTR(FT_Vector_Unit)
2329 LOAD_FUNCPTR(FT_Done_Face)
2330 LOAD_FUNCPTR(FT_Get_Char_Index)
2331 LOAD_FUNCPTR(FT_Get_Module)
2332 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2333 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2334 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2335 LOAD_FUNCPTR(FT_Init_FreeType)
2336 LOAD_FUNCPTR(FT_Load_Glyph)
2337 LOAD_FUNCPTR(FT_Matrix_Multiply)
2338 LOAD_FUNCPTR(FT_MulFix)
2339 LOAD_FUNCPTR(FT_New_Face)
2340 LOAD_FUNCPTR(FT_New_Memory_Face)
2341 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2342 LOAD_FUNCPTR(FT_Outline_Transform)
2343 LOAD_FUNCPTR(FT_Outline_Translate)
2344 LOAD_FUNCPTR(FT_Select_Charmap)
2345 LOAD_FUNCPTR(FT_Set_Charmap)
2346 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2347 LOAD_FUNCPTR(FT_Vector_Transform)
2349 #undef LOAD_FUNCPTR
2350 /* Don't warn if these ones are missing */
2351 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2352 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2353 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2354 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2355 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2356 #ifdef HAVE_FREETYPE_FTWINFNT_H
2357 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2358 #endif
2359 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2360 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2361 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2362 <= 2.0.3 has FT_Sqrt64 */
2363 goto sym_not_found;
2366 if(pFT_Init_FreeType(&library) != 0) {
2367 ERR("Can't init FreeType library\n");
2368 wine_dlclose(ft_handle, NULL, 0);
2369 ft_handle = NULL;
2370 return FALSE;
2372 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2373 if (pFT_Library_Version)
2374 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2376 if (FT_Version.major<=0)
2378 FT_Version.major=2;
2379 FT_Version.minor=0;
2380 FT_Version.patch=5;
2382 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2383 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2384 ((FT_Version.minor << 8) & 0x00ff00) |
2385 ((FT_Version.patch ) & 0x0000ff);
2387 return TRUE;
2389 sym_not_found:
2390 WINE_MESSAGE(
2391 "Wine cannot find certain functions that it needs inside the FreeType\n"
2392 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2393 "FreeType to at least version 2.0.5.\n"
2394 "http://www.freetype.org\n");
2395 wine_dlclose(ft_handle, NULL, 0);
2396 ft_handle = NULL;
2397 return FALSE;
2400 /*************************************************************
2401 * WineEngInit
2403 * Initialize FreeType library and create a list of available faces
2405 BOOL WineEngInit(void)
2407 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2408 static const WCHAR pathW[] = {'P','a','t','h',0};
2409 HKEY hkey;
2410 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2411 LPVOID data;
2412 WCHAR windowsdir[MAX_PATH];
2413 char *unixname;
2414 HANDLE font_mutex;
2415 const char *data_dir;
2417 TRACE("\n");
2419 /* update locale dependent font info in registry */
2420 update_font_info();
2422 if(!init_freetype()) return FALSE;
2424 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2425 ERR("Failed to create font mutex\n");
2426 return FALSE;
2428 WaitForSingleObject(font_mutex, INFINITE);
2430 delete_external_font_keys();
2432 /* load the system bitmap fonts */
2433 load_system_fonts();
2435 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2436 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2437 strcatW(windowsdir, fontsW);
2438 if((unixname = wine_get_unix_file_name(windowsdir)))
2440 ReadFontDir(unixname, FALSE);
2441 HeapFree(GetProcessHeap(), 0, unixname);
2444 /* load the system truetype fonts */
2445 data_dir = wine_get_data_dir();
2446 if (!data_dir) data_dir = wine_get_build_dir();
2447 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2448 strcpy(unixname, data_dir);
2449 strcat(unixname, "/fonts/");
2450 ReadFontDir(unixname, TRUE);
2451 HeapFree(GetProcessHeap(), 0, unixname);
2454 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2455 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2456 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2457 will skip these. */
2458 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2459 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2460 &hkey) == ERROR_SUCCESS) {
2461 LPWSTR valueW;
2462 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2463 &valuelen, &datalen, NULL, NULL);
2465 valuelen++; /* returned value doesn't include room for '\0' */
2466 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2467 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2468 if (valueW && data)
2470 dlen = datalen * sizeof(WCHAR);
2471 vlen = valuelen;
2472 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2473 &dlen) == ERROR_SUCCESS) {
2474 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2476 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2478 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2479 HeapFree(GetProcessHeap(), 0, unixname);
2482 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2484 WCHAR pathW[MAX_PATH];
2485 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2486 BOOL added = FALSE;
2488 sprintfW(pathW, fmtW, windowsdir, data);
2489 if((unixname = wine_get_unix_file_name(pathW)))
2491 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2492 HeapFree(GetProcessHeap(), 0, unixname);
2494 if (!added)
2495 load_font_from_data_dir(data);
2497 /* reset dlen and vlen */
2498 dlen = datalen;
2499 vlen = valuelen;
2502 HeapFree(GetProcessHeap(), 0, data);
2503 HeapFree(GetProcessHeap(), 0, valueW);
2504 RegCloseKey(hkey);
2507 load_fontconfig_fonts();
2509 /* then look in any directories that we've specified in the config file */
2510 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2511 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2513 DWORD len;
2514 LPWSTR valueW;
2515 LPSTR valueA, ptr;
2517 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2519 len += sizeof(WCHAR);
2520 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2521 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2523 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2524 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2525 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2526 TRACE( "got font path %s\n", debugstr_a(valueA) );
2527 ptr = valueA;
2528 while (ptr)
2530 LPSTR next = strchr( ptr, ':' );
2531 if (next) *next++ = 0;
2532 ReadFontDir( ptr, TRUE );
2533 ptr = next;
2535 HeapFree( GetProcessHeap(), 0, valueA );
2537 HeapFree( GetProcessHeap(), 0, valueW );
2539 RegCloseKey(hkey);
2542 DumpFontList();
2543 LoadSubstList();
2544 DumpSubstList();
2545 LoadReplaceList();
2546 update_reg_entries();
2548 init_system_links();
2550 ReleaseMutex(font_mutex);
2551 return TRUE;
2555 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2557 TT_OS2 *pOS2;
2558 TT_HoriHeader *pHori;
2560 LONG ppem;
2562 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2563 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2565 if(height == 0) height = 16;
2567 /* Calc. height of EM square:
2569 * For +ve lfHeight we have
2570 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2571 * Re-arranging gives:
2572 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2574 * For -ve lfHeight we have
2575 * |lfHeight| = ppem
2576 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2577 * with il = winAscent + winDescent - units_per_em]
2581 if(height > 0) {
2582 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2583 ppem = ft_face->units_per_EM * height /
2584 (pHori->Ascender - pHori->Descender);
2585 else
2586 ppem = ft_face->units_per_EM * height /
2587 (pOS2->usWinAscent + pOS2->usWinDescent);
2589 else
2590 ppem = -height;
2592 return ppem;
2595 static struct font_mapping *map_font_file( const char *name )
2597 struct font_mapping *mapping;
2598 struct stat st;
2599 int fd;
2601 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2602 if (fstat( fd, &st ) == -1) goto error;
2604 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2606 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2608 mapping->refcount++;
2609 close( fd );
2610 return mapping;
2613 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2614 goto error;
2616 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2617 close( fd );
2619 if (mapping->data == MAP_FAILED)
2621 HeapFree( GetProcessHeap(), 0, mapping );
2622 return NULL;
2624 mapping->refcount = 1;
2625 mapping->dev = st.st_dev;
2626 mapping->ino = st.st_ino;
2627 mapping->size = st.st_size;
2628 list_add_tail( &mappings_list, &mapping->entry );
2629 return mapping;
2631 error:
2632 close( fd );
2633 return NULL;
2636 static void unmap_font_file( struct font_mapping *mapping )
2638 if (!--mapping->refcount)
2640 list_remove( &mapping->entry );
2641 munmap( mapping->data, mapping->size );
2642 HeapFree( GetProcessHeap(), 0, mapping );
2646 static LONG load_VDMX(GdiFont*, LONG);
2648 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2650 FT_Error err;
2651 FT_Face ft_face;
2652 void *data_ptr;
2653 DWORD data_size;
2655 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2657 if (face->file)
2659 if (!(font->mapping = map_font_file( face->file )))
2661 WARN("failed to map %s\n", debugstr_a(face->file));
2662 return 0;
2664 data_ptr = font->mapping->data;
2665 data_size = font->mapping->size;
2667 else
2669 data_ptr = face->font_data_ptr;
2670 data_size = face->font_data_size;
2673 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2674 if(err) {
2675 ERR("FT_New_Face rets %d\n", err);
2676 return 0;
2679 /* set it here, as load_VDMX needs it */
2680 font->ft_face = ft_face;
2682 if(FT_IS_SCALABLE(ft_face)) {
2683 /* load the VDMX table if we have one */
2684 font->ppem = load_VDMX(font, height);
2685 if(font->ppem == 0)
2686 font->ppem = calc_ppem_for_height(ft_face, height);
2688 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2689 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2690 } else {
2691 font->ppem = height;
2692 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2693 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2695 return ft_face;
2699 static int get_nearest_charset(Face *face, int *cp)
2701 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2702 a single face with the requested charset. The idea is to check if
2703 the selected font supports the current ANSI codepage, if it does
2704 return the corresponding charset, else return the first charset */
2706 CHARSETINFO csi;
2707 int acp = GetACP(), i;
2708 DWORD fs0;
2710 *cp = acp;
2711 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2712 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2713 return csi.ciCharset;
2715 for(i = 0; i < 32; i++) {
2716 fs0 = 1L << i;
2717 if(face->fs.fsCsb[0] & fs0) {
2718 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2719 *cp = csi.ciACP;
2720 return csi.ciCharset;
2722 else
2723 FIXME("TCI failing on %x\n", fs0);
2727 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2728 face->fs.fsCsb[0], face->file);
2729 *cp = acp;
2730 return DEFAULT_CHARSET;
2733 static GdiFont *alloc_font(void)
2735 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2736 ret->gmsize = 1;
2737 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2738 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2739 ret->potm = NULL;
2740 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2741 ret->total_kern_pairs = (DWORD)-1;
2742 ret->kern_pairs = NULL;
2743 list_init(&ret->hfontlist);
2744 list_init(&ret->child_fonts);
2745 return ret;
2748 static void free_font(GdiFont *font)
2750 struct list *cursor, *cursor2;
2751 int i;
2753 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2755 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2756 struct list *first_hfont;
2757 HFONTLIST *hfontlist;
2758 list_remove(cursor);
2759 if(child->font)
2761 first_hfont = list_head(&child->font->hfontlist);
2762 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2763 DeleteObject(hfontlist->hfont);
2764 HeapFree(GetProcessHeap(), 0, hfontlist);
2765 free_font(child->font);
2767 HeapFree(GetProcessHeap(), 0, child);
2770 if (font->ft_face) pFT_Done_Face(font->ft_face);
2771 if (font->mapping) unmap_font_file( font->mapping );
2772 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2773 HeapFree(GetProcessHeap(), 0, font->potm);
2774 HeapFree(GetProcessHeap(), 0, font->name);
2775 for (i = 0; i < font->gmsize; i++)
2776 HeapFree(GetProcessHeap(),0,font->gm[i]);
2777 HeapFree(GetProcessHeap(), 0, font->gm);
2778 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2779 HeapFree(GetProcessHeap(), 0, font);
2783 /*************************************************************
2784 * load_VDMX
2786 * load the vdmx entry for the specified height
2789 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2790 ( ( (FT_ULong)_x4 << 24 ) | \
2791 ( (FT_ULong)_x3 << 16 ) | \
2792 ( (FT_ULong)_x2 << 8 ) | \
2793 (FT_ULong)_x1 )
2795 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2797 typedef struct {
2798 BYTE bCharSet;
2799 BYTE xRatio;
2800 BYTE yStartRatio;
2801 BYTE yEndRatio;
2802 } Ratios;
2804 typedef struct {
2805 WORD recs;
2806 BYTE startsz;
2807 BYTE endsz;
2808 } VDMX_group;
2810 static LONG load_VDMX(GdiFont *font, LONG height)
2812 WORD hdr[3], tmp;
2813 VDMX_group group;
2814 BYTE devXRatio, devYRatio;
2815 USHORT numRecs, numRatios;
2816 DWORD result, offset = -1;
2817 LONG ppem = 0;
2818 int i;
2820 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2822 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2823 return ppem;
2825 /* FIXME: need the real device aspect ratio */
2826 devXRatio = 1;
2827 devYRatio = 1;
2829 numRecs = GET_BE_WORD(hdr[1]);
2830 numRatios = GET_BE_WORD(hdr[2]);
2832 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2833 for(i = 0; i < numRatios; i++) {
2834 Ratios ratio;
2836 offset = (3 * 2) + (i * sizeof(Ratios));
2837 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2838 offset = -1;
2840 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2842 if((ratio.xRatio == 0 &&
2843 ratio.yStartRatio == 0 &&
2844 ratio.yEndRatio == 0) ||
2845 (devXRatio == ratio.xRatio &&
2846 devYRatio >= ratio.yStartRatio &&
2847 devYRatio <= ratio.yEndRatio))
2849 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2850 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2851 offset = GET_BE_WORD(tmp);
2852 break;
2856 if(offset == -1) {
2857 FIXME("No suitable ratio found\n");
2858 return ppem;
2861 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2862 USHORT recs;
2863 BYTE startsz, endsz;
2864 WORD *vTable;
2866 recs = GET_BE_WORD(group.recs);
2867 startsz = group.startsz;
2868 endsz = group.endsz;
2870 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2872 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2873 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2874 if(result == GDI_ERROR) {
2875 FIXME("Failed to retrieve vTable\n");
2876 goto end;
2879 if(height > 0) {
2880 for(i = 0; i < recs; i++) {
2881 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2882 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2883 ppem = GET_BE_WORD(vTable[i * 3]);
2885 if(yMax + -yMin == height) {
2886 font->yMax = yMax;
2887 font->yMin = yMin;
2888 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2889 break;
2891 if(yMax + -yMin > height) {
2892 if(--i < 0) {
2893 ppem = 0;
2894 goto end; /* failed */
2896 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2897 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2898 ppem = GET_BE_WORD(vTable[i * 3]);
2899 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2900 break;
2903 if(!font->yMax) {
2904 ppem = 0;
2905 TRACE("ppem not found for height %d\n", height);
2907 } else {
2908 ppem = -height;
2909 if(ppem < startsz || ppem > endsz)
2910 goto end;
2912 for(i = 0; i < recs; i++) {
2913 USHORT yPelHeight;
2914 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2916 if(yPelHeight > ppem)
2917 break; /* failed */
2919 if(yPelHeight == ppem) {
2920 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2921 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2922 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2923 break;
2927 end:
2928 HeapFree(GetProcessHeap(), 0, vTable);
2931 return ppem;
2934 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2936 if(font->font_desc.hash != fd->hash) return TRUE;
2937 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2938 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2939 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2940 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2943 static void calc_hash(FONT_DESC *pfd)
2945 DWORD hash = 0, *ptr, two_chars;
2946 WORD *pwc;
2947 unsigned int i;
2949 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2950 hash ^= *ptr;
2951 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2952 hash ^= *ptr;
2953 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2954 two_chars = *ptr;
2955 pwc = (WCHAR *)&two_chars;
2956 if(!*pwc) break;
2957 *pwc = toupperW(*pwc);
2958 pwc++;
2959 *pwc = toupperW(*pwc);
2960 hash ^= two_chars;
2961 if(!*pwc) break;
2963 hash ^= !pfd->can_use_bitmap;
2964 pfd->hash = hash;
2965 return;
2968 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
2970 GdiFont *ret;
2971 FONT_DESC fd;
2972 HFONTLIST *hflist;
2973 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2975 fd.lf = *plf;
2976 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2977 fd.can_use_bitmap = can_use_bitmap;
2978 calc_hash(&fd);
2980 /* try the in-use list */
2981 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2982 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2983 if(!fontcmp(ret, &fd)) {
2984 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2985 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2986 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2987 if(hflist->hfont == hfont)
2988 return ret;
2990 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2991 hflist->hfont = hfont;
2992 list_add_head(&ret->hfontlist, &hflist->entry);
2993 return ret;
2997 /* then the unused list */
2998 font_elem_ptr = list_head(&unused_gdi_font_list);
2999 while(font_elem_ptr) {
3000 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3001 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3002 if(!fontcmp(ret, &fd)) {
3003 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3004 assert(list_empty(&ret->hfontlist));
3005 TRACE("Found %p in unused list\n", ret);
3006 list_remove(&ret->entry);
3007 list_add_head(&gdi_font_list, &ret->entry);
3008 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3009 hflist->hfont = hfont;
3010 list_add_head(&ret->hfontlist, &hflist->entry);
3011 return ret;
3014 return NULL;
3018 /*************************************************************
3019 * create_child_font_list
3021 static BOOL create_child_font_list(GdiFont *font)
3023 BOOL ret = FALSE;
3024 SYSTEM_LINKS *font_link;
3025 CHILD_FONT *font_link_entry, *new_child;
3027 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3029 if(!strcmpW(font_link->font_name, font->name))
3031 TRACE("found entry in system list\n");
3032 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3034 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3035 new_child->face = font_link_entry->face;
3036 new_child->font = NULL;
3037 list_add_tail(&font->child_fonts, &new_child->entry);
3038 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3040 ret = TRUE;
3041 break;
3045 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3046 * Sans Serif. This is how asian windows get default fallbacks for fonts
3048 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3049 font->charset != OEM_CHARSET &&
3050 strcmpW(font->name,szDefaultFallbackLink) != 0)
3051 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3053 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3055 TRACE("found entry in default fallback list\n");
3056 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3058 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3059 new_child->face = font_link_entry->face;
3060 new_child->font = NULL;
3061 list_add_tail(&font->child_fonts, &new_child->entry);
3062 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3064 ret = TRUE;
3065 break;
3069 return ret;
3072 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3074 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3076 if (pFT_Set_Charmap)
3078 FT_Int i;
3079 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3081 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3083 for (i = 0; i < ft_face->num_charmaps; i++)
3085 if (ft_face->charmaps[i]->encoding == encoding)
3087 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3088 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3090 switch (ft_face->charmaps[i]->platform_id)
3092 default:
3093 cmap_def = ft_face->charmaps[i];
3094 break;
3095 case 0: /* Apple Unicode */
3096 cmap0 = ft_face->charmaps[i];
3097 break;
3098 case 1: /* Macintosh */
3099 cmap1 = ft_face->charmaps[i];
3100 break;
3101 case 2: /* ISO */
3102 cmap2 = ft_face->charmaps[i];
3103 break;
3104 case 3: /* Microsoft */
3105 cmap3 = ft_face->charmaps[i];
3106 break;
3110 if (cmap3) /* prefer Microsoft cmap table */
3111 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3112 else if (cmap1)
3113 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3114 else if (cmap2)
3115 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3116 else if (cmap0)
3117 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3118 else if (cmap_def)
3119 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3121 return ft_err == FT_Err_Ok;
3124 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3127 /*************************************************************
3128 * WineEngCreateFontInstance
3131 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3133 GdiFont *ret;
3134 Face *face, *best, *best_bitmap;
3135 Family *family, *last_resort_family;
3136 struct list *family_elem_ptr, *face_elem_ptr;
3137 INT height, width = 0;
3138 unsigned int score = 0, new_score;
3139 signed int diff = 0, newdiff;
3140 BOOL bd, it, can_use_bitmap;
3141 LOGFONTW lf;
3142 CHARSETINFO csi;
3143 HFONTLIST *hflist;
3145 EnterCriticalSection( &freetype_cs );
3147 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3149 struct list *first_hfont = list_head(&ret->hfontlist);
3150 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3151 if(hflist->hfont == hfont)
3153 LeaveCriticalSection( &freetype_cs );
3154 return ret;
3158 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3160 LeaveCriticalSection( &freetype_cs );
3161 return NULL;
3163 lf.lfWidth = abs(lf.lfWidth);
3165 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3167 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3168 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3169 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3170 lf.lfEscapement);
3172 /* check the cache first */
3173 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3174 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3175 LeaveCriticalSection( &freetype_cs );
3176 return ret;
3179 TRACE("not in cache\n");
3180 if(list_empty(&font_list)) /* No fonts installed */
3182 TRACE("No fonts installed\n");
3183 LeaveCriticalSection( &freetype_cs );
3184 return NULL;
3186 if(!have_installed_roman_font)
3188 TRACE("No roman font installed\n");
3189 LeaveCriticalSection( &freetype_cs );
3190 return NULL;
3193 ret = alloc_font();
3195 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3196 ret->font_desc.lf = lf;
3197 ret->font_desc.can_use_bitmap = can_use_bitmap;
3198 calc_hash(&ret->font_desc);
3199 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3200 hflist->hfont = hfont;
3201 list_add_head(&ret->hfontlist, &hflist->entry);
3204 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3205 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3206 original value lfCharSet. Note this is a special case for
3207 Symbol and doesn't happen at least for "Wingdings*" */
3209 if(!strcmpiW(lf.lfFaceName, SymbolW))
3210 lf.lfCharSet = SYMBOL_CHARSET;
3212 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3213 switch(lf.lfCharSet) {
3214 case DEFAULT_CHARSET:
3215 csi.fs.fsCsb[0] = 0;
3216 break;
3217 default:
3218 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3219 csi.fs.fsCsb[0] = 0;
3220 break;
3224 family = NULL;
3225 if(lf.lfFaceName[0] != '\0') {
3226 FontSubst *psub;
3227 SYSTEM_LINKS *font_link;
3228 CHILD_FONT *font_link_entry;
3229 LPWSTR FaceName = lf.lfFaceName;
3232 * Check for a leading '@' this signals that the font is being
3233 * requested in tategaki mode (vertical writing substitution) but
3234 * does not affect the fontface that is to be selected.
3236 if (lf.lfFaceName[0]=='@')
3237 FaceName = &lf.lfFaceName[1];
3239 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3241 if(psub) {
3242 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3243 debugstr_w(psub->to.name));
3244 strcpyW(FaceName, psub->to.name);
3247 /* We want a match on name and charset or just name if
3248 charset was DEFAULT_CHARSET. If the latter then
3249 we fixup the returned charset later in get_nearest_charset
3250 where we'll either use the charset of the current ansi codepage
3251 or if that's unavailable the first charset that the font supports.
3253 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3254 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3255 if(!strcmpiW(family->FamilyName, FaceName)) {
3256 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3257 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3258 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3259 if(face->scalable || can_use_bitmap)
3260 goto found;
3266 * Try check the SystemLink list first for a replacement font.
3267 * We may find good replacements there.
3269 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3271 if(!strcmpiW(font_link->font_name, FaceName))
3273 TRACE("found entry in system list\n");
3274 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3276 face = font_link_entry->face;
3277 family = face->family;
3278 if(csi.fs.fsCsb[0] &
3279 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3281 if(face->scalable || can_use_bitmap)
3282 goto found;
3289 /* If requested charset was DEFAULT_CHARSET then try using charset
3290 corresponding to the current ansi codepage */
3291 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3293 INT acp = GetACP();
3294 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3295 FIXME("TCI failed on codepage %d\n", acp);
3296 csi.fs.fsCsb[0] = 0;
3297 } else
3298 lf.lfCharSet = csi.ciCharset;
3301 /* Face families are in the top 4 bits of lfPitchAndFamily,
3302 so mask with 0xF0 before testing */
3304 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3305 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3306 strcpyW(lf.lfFaceName, defFixed);
3307 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3308 strcpyW(lf.lfFaceName, defSerif);
3309 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3310 strcpyW(lf.lfFaceName, defSans);
3311 else
3312 strcpyW(lf.lfFaceName, defSans);
3313 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3314 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3315 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3316 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3317 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3318 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3319 if(face->scalable || can_use_bitmap)
3320 goto found;
3325 last_resort_family = NULL;
3326 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3327 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3328 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3329 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3330 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3331 if(face->scalable)
3332 goto found;
3333 if(can_use_bitmap && !last_resort_family)
3334 last_resort_family = family;
3339 if(last_resort_family) {
3340 family = last_resort_family;
3341 csi.fs.fsCsb[0] = 0;
3342 goto found;
3345 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3346 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3347 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3348 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3349 if(face->scalable) {
3350 csi.fs.fsCsb[0] = 0;
3351 WARN("just using first face for now\n");
3352 goto found;
3354 if(can_use_bitmap && !last_resort_family)
3355 last_resort_family = family;
3358 if(!last_resort_family) {
3359 FIXME("can't find a single appropriate font - bailing\n");
3360 free_font(ret);
3361 LeaveCriticalSection( &freetype_cs );
3362 return NULL;
3365 WARN("could only find a bitmap font - this will probably look awful!\n");
3366 family = last_resort_family;
3367 csi.fs.fsCsb[0] = 0;
3369 found:
3370 it = lf.lfItalic ? 1 : 0;
3371 bd = lf.lfWeight > 550 ? 1 : 0;
3373 height = GDI_ROUND( (double)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3374 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3376 face = best = best_bitmap = NULL;
3377 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3379 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3381 BOOL italic, bold;
3383 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3384 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3385 new_score = (italic ^ it) + (bold ^ bd);
3386 if(!best || new_score <= score)
3388 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3389 italic, bold, it, bd);
3390 score = new_score;
3391 best = face;
3392 if(best->scalable && score == 0) break;
3393 if(!best->scalable)
3395 if(height > 0)
3396 newdiff = height - (signed int)(best->size.height);
3397 else
3398 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3399 if(!best_bitmap || new_score < score ||
3400 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3402 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3403 diff = newdiff;
3404 best_bitmap = best;
3405 if(score == 0 && diff == 0) break;
3411 if(best)
3412 face = best->scalable ? best : best_bitmap;
3413 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3414 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3416 ret->fs = face->fs;
3418 if(csi.fs.fsCsb[0]) {
3419 ret->charset = lf.lfCharSet;
3420 ret->codepage = csi.ciACP;
3422 else
3423 ret->charset = get_nearest_charset(face, &ret->codepage);
3425 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3426 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3428 ret->aveWidth = height ? lf.lfWidth : 0;
3430 if(!face->scalable) {
3431 /* Windows uses integer scaling factors for bitmap fonts */
3432 INT scale, scaled_height;
3434 if (height != 0) height = diff;
3435 height += face->size.height;
3437 scale = (height + face->size.height - 1) / face->size.height;
3438 scaled_height = scale * face->size.height;
3439 /* XP allows not more than 10% deviation */
3440 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3441 ret->scale_y = scale;
3443 width = face->size.x_ppem >> 6;
3444 height = face->size.y_ppem >> 6;
3446 else
3447 ret->scale_y = 1.0;
3448 TRACE("font scale y: %f\n", ret->scale_y);
3450 ret->ft_face = OpenFontFace(ret, face, width, height);
3452 if (!ret->ft_face)
3454 free_font( ret );
3455 LeaveCriticalSection( &freetype_cs );
3456 return 0;
3459 ret->ntmFlags = face->ntmFlags;
3461 if (ret->charset == SYMBOL_CHARSET &&
3462 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3463 /* No ops */
3465 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3466 /* No ops */
3468 else {
3469 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3472 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3473 ret->name = strdupW(family->FamilyName);
3474 ret->underline = lf.lfUnderline ? 0xff : 0;
3475 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3476 create_child_font_list(ret);
3478 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3480 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3481 if (length != GDI_ERROR)
3483 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3484 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3485 TRACE("Loaded GSUB table of %i bytes\n",length);
3489 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3491 list_add_head(&gdi_font_list, &ret->entry);
3492 LeaveCriticalSection( &freetype_cs );
3493 return ret;
3496 static void dump_gdi_font_list(void)
3498 GdiFont *gdiFont;
3499 struct list *elem_ptr;
3501 TRACE("---------- gdiFont Cache ----------\n");
3502 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3503 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3504 TRACE("gdiFont=%p %s %d\n",
3505 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3508 TRACE("---------- Unused gdiFont Cache ----------\n");
3509 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3510 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3511 TRACE("gdiFont=%p %s %d\n",
3512 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3516 /*************************************************************
3517 * WineEngDestroyFontInstance
3519 * free the gdiFont associated with this handle
3522 BOOL WineEngDestroyFontInstance(HFONT handle)
3524 GdiFont *gdiFont;
3525 HFONTLIST *hflist;
3526 BOOL ret = FALSE;
3527 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3528 int i = 0;
3530 EnterCriticalSection( &freetype_cs );
3532 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3534 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3535 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3536 if(hflist->hfont == handle)
3538 TRACE("removing child font %p from child list\n", gdiFont);
3539 list_remove(&gdiFont->entry);
3540 LeaveCriticalSection( &freetype_cs );
3541 return TRUE;
3545 TRACE("destroying hfont=%p\n", handle);
3546 if(TRACE_ON(font))
3547 dump_gdi_font_list();
3549 font_elem_ptr = list_head(&gdi_font_list);
3550 while(font_elem_ptr) {
3551 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3552 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3554 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3555 while(hfontlist_elem_ptr) {
3556 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3557 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3558 if(hflist->hfont == handle) {
3559 list_remove(&hflist->entry);
3560 HeapFree(GetProcessHeap(), 0, hflist);
3561 ret = TRUE;
3564 if(list_empty(&gdiFont->hfontlist)) {
3565 TRACE("Moving to Unused list\n");
3566 list_remove(&gdiFont->entry);
3567 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3572 font_elem_ptr = list_head(&unused_gdi_font_list);
3573 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3574 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3575 while(font_elem_ptr) {
3576 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3577 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3578 TRACE("freeing %p\n", gdiFont);
3579 list_remove(&gdiFont->entry);
3580 free_font(gdiFont);
3582 LeaveCriticalSection( &freetype_cs );
3583 return ret;
3586 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3587 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3589 GdiFont *font;
3590 LONG width, height;
3592 if (face->cached_enum_data)
3594 TRACE("Cached\n");
3595 *pelf = face->cached_enum_data->elf;
3596 *pntm = face->cached_enum_data->ntm;
3597 *ptype = face->cached_enum_data->type;
3598 return;
3601 font = alloc_font();
3603 if(face->scalable) {
3604 height = -2048; /* 2048 is the most common em size */
3605 width = 0;
3606 } else {
3607 height = face->size.y_ppem >> 6;
3608 width = face->size.x_ppem >> 6;
3610 font->scale_y = 1.0;
3612 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3614 free_font(font);
3615 return;
3618 font->name = strdupW(face->family->FamilyName);
3619 font->ntmFlags = face->ntmFlags;
3621 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3623 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3625 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3627 lstrcpynW(pelf->elfLogFont.lfFaceName,
3628 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3629 LF_FACESIZE);
3630 lstrcpynW(pelf->elfFullName,
3631 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3632 LF_FULLFACESIZE);
3633 lstrcpynW(pelf->elfStyle,
3634 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3635 LF_FACESIZE);
3637 else
3639 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3641 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3643 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3644 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3645 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3648 pntm->ntmTm.ntmFlags = face->ntmFlags;
3649 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3650 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3651 pntm->ntmFontSig = face->fs;
3653 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3655 pelf->elfLogFont.lfEscapement = 0;
3656 pelf->elfLogFont.lfOrientation = 0;
3657 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3658 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3659 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3660 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3661 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3662 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3663 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3664 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3665 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3666 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3667 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3669 *ptype = 0;
3670 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3671 *ptype |= TRUETYPE_FONTTYPE;
3672 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3673 *ptype |= DEVICE_FONTTYPE;
3674 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3675 *ptype |= RASTER_FONTTYPE;
3677 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3678 if (face->cached_enum_data)
3680 face->cached_enum_data->elf = *pelf;
3681 face->cached_enum_data->ntm = *pntm;
3682 face->cached_enum_data->type = *ptype;
3685 free_font(font);
3688 /*************************************************************
3689 * WineEngEnumFonts
3692 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3694 Family *family;
3695 Face *face;
3696 struct list *family_elem_ptr, *face_elem_ptr;
3697 ENUMLOGFONTEXW elf;
3698 NEWTEXTMETRICEXW ntm;
3699 DWORD type;
3700 FONTSIGNATURE fs;
3701 CHARSETINFO csi;
3702 LOGFONTW lf;
3703 int i;
3705 if (!plf)
3707 lf.lfCharSet = DEFAULT_CHARSET;
3708 lf.lfPitchAndFamily = 0;
3709 lf.lfFaceName[0] = 0;
3710 plf = &lf;
3713 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3715 EnterCriticalSection( &freetype_cs );
3716 if(plf->lfFaceName[0]) {
3717 FontSubst *psub;
3718 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3720 if(psub) {
3721 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3722 debugstr_w(psub->to.name));
3723 lf = *plf;
3724 strcpyW(lf.lfFaceName, psub->to.name);
3725 plf = &lf;
3728 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3729 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3730 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3731 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3732 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3733 GetEnumStructs(face, &elf, &ntm, &type);
3734 for(i = 0; i < 32; i++) {
3735 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3736 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3737 strcpyW(elf.elfScript, OEM_DOSW);
3738 i = 32; /* break out of loop */
3739 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3740 continue;
3741 else {
3742 fs.fsCsb[0] = 1L << i;
3743 fs.fsCsb[1] = 0;
3744 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3745 TCI_SRCFONTSIG))
3746 csi.ciCharset = DEFAULT_CHARSET;
3747 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3748 if(csi.ciCharset != DEFAULT_CHARSET) {
3749 elf.elfLogFont.lfCharSet =
3750 ntm.ntmTm.tmCharSet = csi.ciCharset;
3751 if(ElfScriptsW[i])
3752 strcpyW(elf.elfScript, ElfScriptsW[i]);
3753 else
3754 FIXME("Unknown elfscript for bit %d\n", i);
3757 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3758 debugstr_w(elf.elfLogFont.lfFaceName),
3759 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3760 csi.ciCharset, type, debugstr_w(elf.elfScript),
3761 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3762 ntm.ntmTm.ntmFlags);
3763 /* release section before callback (FIXME) */
3764 LeaveCriticalSection( &freetype_cs );
3765 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3766 EnterCriticalSection( &freetype_cs );
3771 } else {
3772 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3773 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3774 face_elem_ptr = list_head(&family->faces);
3775 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3776 GetEnumStructs(face, &elf, &ntm, &type);
3777 for(i = 0; i < 32; i++) {
3778 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3779 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3780 strcpyW(elf.elfScript, OEM_DOSW);
3781 i = 32; /* break out of loop */
3782 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3783 continue;
3784 else {
3785 fs.fsCsb[0] = 1L << i;
3786 fs.fsCsb[1] = 0;
3787 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3788 TCI_SRCFONTSIG))
3789 csi.ciCharset = DEFAULT_CHARSET;
3790 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3791 if(csi.ciCharset != DEFAULT_CHARSET) {
3792 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3793 csi.ciCharset;
3794 if(ElfScriptsW[i])
3795 strcpyW(elf.elfScript, ElfScriptsW[i]);
3796 else
3797 FIXME("Unknown elfscript for bit %d\n", i);
3800 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3801 debugstr_w(elf.elfLogFont.lfFaceName),
3802 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3803 csi.ciCharset, type, debugstr_w(elf.elfScript),
3804 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3805 ntm.ntmTm.ntmFlags);
3806 /* release section before callback (FIXME) */
3807 LeaveCriticalSection( &freetype_cs );
3808 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3809 EnterCriticalSection( &freetype_cs );
3813 LeaveCriticalSection( &freetype_cs );
3814 return 1;
3817 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3819 pt->x.value = vec->x >> 6;
3820 pt->x.fract = (vec->x & 0x3f) << 10;
3821 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3822 pt->y.value = vec->y >> 6;
3823 pt->y.fract = (vec->y & 0x3f) << 10;
3824 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3825 return;
3828 /***************************************************
3829 * According to the MSDN documentation on WideCharToMultiByte,
3830 * certain codepages cannot set the default_used parameter.
3831 * This returns TRUE if the codepage can set that parameter, false else
3832 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3834 static BOOL codepage_sets_default_used(UINT codepage)
3836 switch (codepage)
3838 case CP_UTF7:
3839 case CP_UTF8:
3840 case CP_SYMBOL:
3841 return FALSE;
3842 default:
3843 return TRUE;
3848 * GSUB Table handling functions
3851 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3853 const GSUB_CoverageFormat1* cf1;
3855 cf1 = (GSUB_CoverageFormat1*)table;
3857 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3859 int count = GET_BE_WORD(cf1->GlyphCount);
3860 int i;
3861 TRACE("Coverage Format 1, %i glyphs\n",count);
3862 for (i = 0; i < count; i++)
3863 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3864 return i;
3865 return -1;
3867 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3869 const GSUB_CoverageFormat2* cf2;
3870 int i;
3871 int count;
3872 cf2 = (GSUB_CoverageFormat2*)cf1;
3874 count = GET_BE_WORD(cf2->RangeCount);
3875 TRACE("Coverage Format 2, %i ranges\n",count);
3876 for (i = 0; i < count; i++)
3878 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3879 return -1;
3880 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3881 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3883 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3884 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3887 return -1;
3889 else
3890 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3892 return -1;
3895 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3897 const GSUB_ScriptList *script;
3898 const GSUB_Script *deflt = NULL;
3899 int i;
3900 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3902 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3903 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3905 const GSUB_Script *scr;
3906 int offset;
3908 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3909 scr = (GSUB_Script*)((LPBYTE)script + offset);
3911 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3912 return scr;
3913 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3914 deflt = scr;
3916 return deflt;
3919 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3921 int i;
3922 int offset;
3923 const GSUB_LangSys *Lang;
3925 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3927 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3929 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3930 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3932 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3933 return Lang;
3935 offset = GET_BE_WORD(script->DefaultLangSys);
3936 if (offset)
3938 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3939 return Lang;
3941 return NULL;
3944 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3946 int i;
3947 const GSUB_FeatureList *feature;
3948 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3950 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
3951 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3953 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3954 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3956 const GSUB_Feature *feat;
3957 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3958 return feat;
3961 return NULL;
3964 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3966 int i;
3967 int offset;
3968 const GSUB_LookupList *lookup;
3969 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3971 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3972 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3974 const GSUB_LookupTable *look;
3975 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3976 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3977 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3978 if (GET_BE_WORD(look->LookupType) != 1)
3979 FIXME("We only handle SubType 1\n");
3980 else
3982 int j;
3984 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3986 const GSUB_SingleSubstFormat1 *ssf1;
3987 offset = GET_BE_WORD(look->SubTable[j]);
3988 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3989 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3991 int offset = GET_BE_WORD(ssf1->Coverage);
3992 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
3993 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
3995 TRACE(" Glyph 0x%x ->",glyph);
3996 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
3997 TRACE(" 0x%x\n",glyph);
4000 else
4002 const GSUB_SingleSubstFormat2 *ssf2;
4003 INT index;
4004 INT offset;
4006 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4007 offset = GET_BE_WORD(ssf1->Coverage);
4008 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4009 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4010 TRACE(" Coverage index %i\n",index);
4011 if (index != -1)
4013 TRACE(" Glyph is 0x%x ->",glyph);
4014 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4015 TRACE("0x%x\n",glyph);
4021 return glyph;
4024 static const char* get_opentype_script(const GdiFont *font)
4027 * I am not sure if this is the correct way to generate our script tag
4030 switch (font->charset)
4032 case ANSI_CHARSET: return "latn";
4033 case BALTIC_CHARSET: return "latn"; /* ?? */
4034 case CHINESEBIG5_CHARSET: return "hani";
4035 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4036 case GB2312_CHARSET: return "hani";
4037 case GREEK_CHARSET: return "grek";
4038 case HANGUL_CHARSET: return "hang";
4039 case RUSSIAN_CHARSET: return "cyrl";
4040 case SHIFTJIS_CHARSET: return "kana";
4041 case TURKISH_CHARSET: return "latn"; /* ?? */
4042 case VIETNAMESE_CHARSET: return "latn";
4043 case JOHAB_CHARSET: return "latn"; /* ?? */
4044 case ARABIC_CHARSET: return "arab";
4045 case HEBREW_CHARSET: return "hebr";
4046 case THAI_CHARSET: return "thai";
4047 default: return "latn";
4051 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4053 const GSUB_Header *header;
4054 const GSUB_Script *script;
4055 const GSUB_LangSys *language;
4056 const GSUB_Feature *feature;
4058 if (!font->GSUB_Table)
4059 return glyph;
4061 header = font->GSUB_Table;
4063 script = GSUB_get_script_table(header, get_opentype_script(font));
4064 if (!script)
4066 TRACE("Script not found\n");
4067 return glyph;
4069 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4070 if (!language)
4072 TRACE("Language not found\n");
4073 return glyph;
4075 feature = GSUB_get_feature(header, language, "vrt2");
4076 if (!feature)
4077 feature = GSUB_get_feature(header, language, "vert");
4078 if (!feature)
4080 TRACE("vrt2/vert feature not found\n");
4081 return glyph;
4083 return GSUB_apply_feature(header, feature, glyph);
4086 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4088 FT_UInt glyphId;
4090 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4091 WCHAR wc = (WCHAR)glyph;
4092 BOOL default_used;
4093 BOOL *default_used_pointer;
4094 FT_UInt ret;
4095 char buf;
4096 default_used_pointer = NULL;
4097 default_used = FALSE;
4098 if (codepage_sets_default_used(font->codepage))
4099 default_used_pointer = &default_used;
4100 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4101 ret = 0;
4102 else
4103 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4104 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4105 return get_GSUB_vert_glyph(font,ret);
4108 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4109 glyph = glyph + 0xf000;
4110 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4111 return get_GSUB_vert_glyph(font,glyphId);
4114 /*************************************************************
4115 * WineEngGetGlyphIndices
4118 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4119 LPWORD pgi, DWORD flags)
4121 int i;
4122 int default_char = -1;
4124 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4126 for(i = 0; i < count; i++)
4128 pgi[i] = get_glyph_index(font, lpstr[i]);
4129 if (pgi[i] == 0)
4131 if (default_char == -1)
4133 if (FT_IS_SFNT(font->ft_face))
4135 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4136 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4138 else
4140 TEXTMETRICW textm;
4141 WineEngGetTextMetrics(font, &textm);
4142 default_char = textm.tmDefaultChar;
4145 pgi[i] = default_char;
4148 return count;
4151 /*************************************************************
4152 * WineEngGetGlyphOutline
4154 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4155 * except that the first parameter is the HWINEENGFONT of the font in
4156 * question rather than an HDC.
4159 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4160 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4161 const MAT2* lpmat)
4163 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4164 FT_Face ft_face = incoming_font->ft_face;
4165 GdiFont *font = incoming_font;
4166 FT_UInt glyph_index;
4167 DWORD width, height, pitch, needed = 0;
4168 FT_Bitmap ft_bitmap;
4169 FT_Error err;
4170 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4171 FT_Angle angle = 0;
4172 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4173 float widthRatio = 1.0;
4174 FT_Matrix transMat = identityMat;
4175 BOOL needsTransform = FALSE;
4176 BOOL tategaki = (font->GSUB_Table != NULL);
4177 UINT original_index;
4180 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4181 buflen, buf, lpmat);
4183 EnterCriticalSection( &freetype_cs );
4185 if(format & GGO_GLYPH_INDEX) {
4186 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4187 original_index = glyph;
4188 format &= ~GGO_GLYPH_INDEX;
4189 } else {
4190 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4191 ft_face = font->ft_face;
4192 original_index = glyph_index;
4195 /* tategaki never appears to happen to lower glyph index */
4196 if (glyph_index < TATEGAKI_LOWER_BOUND )
4197 tategaki = FALSE;
4199 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4200 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4201 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4202 font->gmsize * sizeof(GM*));
4203 } else {
4204 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4205 *lpgm = FONT_GM(font,original_index)->gm;
4206 LeaveCriticalSection( &freetype_cs );
4207 return 1; /* FIXME */
4211 if (!font->gm[original_index / GM_BLOCK_SIZE])
4212 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4214 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4215 load_flags |= FT_LOAD_NO_BITMAP;
4217 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4219 if(err) {
4220 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4221 LeaveCriticalSection( &freetype_cs );
4222 return GDI_ERROR;
4225 /* Scaling factor */
4226 if (font->aveWidth && font->potm)
4228 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4229 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4231 else
4232 widthRatio = font->scale_y;
4234 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4235 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4237 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4238 lsb = left >> 6;
4239 bbx = (right - left) >> 6;
4241 /* Scaling transform */
4242 if(font->aveWidth) {
4243 FT_Matrix scaleMat;
4244 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4245 scaleMat.xy = 0;
4246 scaleMat.yx = 0;
4247 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4249 pFT_Matrix_Multiply(&scaleMat, &transMat);
4250 needsTransform = TRUE;
4253 /* Slant transform */
4254 if (font->fake_italic) {
4255 FT_Matrix slantMat;
4257 slantMat.xx = (1 << 16);
4258 slantMat.xy = ((1 << 16) >> 2);
4259 slantMat.yx = 0;
4260 slantMat.yy = (1 << 16);
4261 pFT_Matrix_Multiply(&slantMat, &transMat);
4262 needsTransform = TRUE;
4265 /* Rotation transform */
4266 if(font->orientation && !tategaki) {
4267 FT_Matrix rotationMat;
4268 FT_Vector vecAngle;
4269 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4270 pFT_Vector_Unit(&vecAngle, angle);
4271 rotationMat.xx = vecAngle.x;
4272 rotationMat.xy = -vecAngle.y;
4273 rotationMat.yx = -rotationMat.xy;
4274 rotationMat.yy = rotationMat.xx;
4276 pFT_Matrix_Multiply(&rotationMat, &transMat);
4277 needsTransform = TRUE;
4280 /* Extra transformation specified by caller */
4281 if (lpmat) {
4282 FT_Matrix extraMat;
4283 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4284 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4285 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4286 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4287 pFT_Matrix_Multiply(&extraMat, &transMat);
4288 needsTransform = TRUE;
4291 if(!needsTransform) {
4292 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4293 bottom = (ft_face->glyph->metrics.horiBearingY -
4294 ft_face->glyph->metrics.height) & -64;
4295 lpgm->gmCellIncX = adv;
4296 lpgm->gmCellIncY = 0;
4297 } else {
4298 INT xc, yc;
4299 FT_Vector vec;
4300 for(xc = 0; xc < 2; xc++) {
4301 for(yc = 0; yc < 2; yc++) {
4302 vec.x = (ft_face->glyph->metrics.horiBearingX +
4303 xc * ft_face->glyph->metrics.width);
4304 vec.y = ft_face->glyph->metrics.horiBearingY -
4305 yc * ft_face->glyph->metrics.height;
4306 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4307 pFT_Vector_Transform(&vec, &transMat);
4308 if(xc == 0 && yc == 0) {
4309 left = right = vec.x;
4310 top = bottom = vec.y;
4311 } else {
4312 if(vec.x < left) left = vec.x;
4313 else if(vec.x > right) right = vec.x;
4314 if(vec.y < bottom) bottom = vec.y;
4315 else if(vec.y > top) top = vec.y;
4319 left = left & -64;
4320 right = (right + 63) & -64;
4321 bottom = bottom & -64;
4322 top = (top + 63) & -64;
4324 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4325 vec.x = ft_face->glyph->metrics.horiAdvance;
4326 vec.y = 0;
4327 pFT_Vector_Transform(&vec, &transMat);
4328 lpgm->gmCellIncX = (vec.x+63) >> 6;
4329 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4331 lpgm->gmBlackBoxX = (right - left) >> 6;
4332 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4333 lpgm->gmptGlyphOrigin.x = left >> 6;
4334 lpgm->gmptGlyphOrigin.y = top >> 6;
4336 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4338 FONT_GM(font,original_index)->gm = *lpgm;
4339 FONT_GM(font,original_index)->adv = adv;
4340 FONT_GM(font,original_index)->lsb = lsb;
4341 FONT_GM(font,original_index)->bbx = bbx;
4342 FONT_GM(font,original_index)->init = TRUE;
4345 if(format == GGO_METRICS)
4347 LeaveCriticalSection( &freetype_cs );
4348 return 1; /* FIXME */
4351 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4352 TRACE("loaded a bitmap\n");
4353 LeaveCriticalSection( &freetype_cs );
4354 return GDI_ERROR;
4357 switch(format) {
4358 case GGO_BITMAP:
4359 width = lpgm->gmBlackBoxX;
4360 height = lpgm->gmBlackBoxY;
4361 pitch = ((width + 31) >> 5) << 2;
4362 needed = pitch * height;
4364 if(!buf || !buflen) break;
4366 switch(ft_face->glyph->format) {
4367 case ft_glyph_format_bitmap:
4369 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4370 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4371 INT h = ft_face->glyph->bitmap.rows;
4372 while(h--) {
4373 memcpy(dst, src, w);
4374 src += ft_face->glyph->bitmap.pitch;
4375 dst += pitch;
4377 break;
4380 case ft_glyph_format_outline:
4381 ft_bitmap.width = width;
4382 ft_bitmap.rows = height;
4383 ft_bitmap.pitch = pitch;
4384 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4385 ft_bitmap.buffer = buf;
4387 if(needsTransform) {
4388 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4391 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4393 /* Note: FreeType will only set 'black' bits for us. */
4394 memset(buf, 0, needed);
4395 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4396 break;
4398 default:
4399 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4400 LeaveCriticalSection( &freetype_cs );
4401 return GDI_ERROR;
4403 break;
4405 case GGO_GRAY2_BITMAP:
4406 case GGO_GRAY4_BITMAP:
4407 case GGO_GRAY8_BITMAP:
4408 case WINE_GGO_GRAY16_BITMAP:
4410 unsigned int mult, row, col;
4411 BYTE *start, *ptr;
4413 width = lpgm->gmBlackBoxX;
4414 height = lpgm->gmBlackBoxY;
4415 pitch = (width + 3) / 4 * 4;
4416 needed = pitch * height;
4418 if(!buf || !buflen) break;
4420 switch(ft_face->glyph->format) {
4421 case ft_glyph_format_bitmap:
4423 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4424 INT h = ft_face->glyph->bitmap.rows;
4425 INT x;
4426 while(h--) {
4427 for(x = 0; x < pitch; x++)
4429 if(x < ft_face->glyph->bitmap.width)
4430 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4431 else
4432 dst[x] = 0;
4434 src += ft_face->glyph->bitmap.pitch;
4435 dst += pitch;
4437 LeaveCriticalSection( &freetype_cs );
4438 return needed;
4440 case ft_glyph_format_outline:
4442 ft_bitmap.width = width;
4443 ft_bitmap.rows = height;
4444 ft_bitmap.pitch = pitch;
4445 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4446 ft_bitmap.buffer = buf;
4448 if(needsTransform)
4449 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4451 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4453 memset(ft_bitmap.buffer, 0, buflen);
4455 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4457 if(format == GGO_GRAY2_BITMAP)
4458 mult = 4;
4459 else if(format == GGO_GRAY4_BITMAP)
4460 mult = 16;
4461 else if(format == GGO_GRAY8_BITMAP)
4462 mult = 64;
4463 else /* format == WINE_GGO_GRAY16_BITMAP */
4465 LeaveCriticalSection( &freetype_cs );
4466 return needed;
4468 break;
4470 default:
4471 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4472 LeaveCriticalSection( &freetype_cs );
4473 return GDI_ERROR;
4476 start = buf;
4477 for(row = 0; row < height; row++) {
4478 ptr = start;
4479 for(col = 0; col < width; col++, ptr++) {
4480 *ptr = (((int)*ptr) * mult + 128) / 256;
4482 start += pitch;
4484 break;
4487 case GGO_NATIVE:
4489 int contour, point = 0, first_pt;
4490 FT_Outline *outline = &ft_face->glyph->outline;
4491 TTPOLYGONHEADER *pph;
4492 TTPOLYCURVE *ppc;
4493 DWORD pph_start, cpfx, type;
4495 if(buflen == 0) buf = NULL;
4497 if (needsTransform && buf) {
4498 pFT_Outline_Transform(outline, &transMat);
4501 for(contour = 0; contour < outline->n_contours; contour++) {
4502 pph_start = needed;
4503 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4504 first_pt = point;
4505 if(buf) {
4506 pph->dwType = TT_POLYGON_TYPE;
4507 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4509 needed += sizeof(*pph);
4510 point++;
4511 while(point <= outline->contours[contour]) {
4512 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4513 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4514 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4515 cpfx = 0;
4516 do {
4517 if(buf)
4518 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4519 cpfx++;
4520 point++;
4521 } while(point <= outline->contours[contour] &&
4522 (outline->tags[point] & FT_Curve_Tag_On) ==
4523 (outline->tags[point-1] & FT_Curve_Tag_On));
4524 /* At the end of a contour Windows adds the start point, but
4525 only for Beziers */
4526 if(point > outline->contours[contour] &&
4527 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4528 if(buf)
4529 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4530 cpfx++;
4531 } else if(point <= outline->contours[contour] &&
4532 outline->tags[point] & FT_Curve_Tag_On) {
4533 /* add closing pt for bezier */
4534 if(buf)
4535 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4536 cpfx++;
4537 point++;
4539 if(buf) {
4540 ppc->wType = type;
4541 ppc->cpfx = cpfx;
4543 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4545 if(buf)
4546 pph->cb = needed - pph_start;
4548 break;
4550 case GGO_BEZIER:
4552 /* Convert the quadratic Beziers to cubic Beziers.
4553 The parametric eqn for a cubic Bezier is, from PLRM:
4554 r(t) = at^3 + bt^2 + ct + r0
4555 with the control points:
4556 r1 = r0 + c/3
4557 r2 = r1 + (c + b)/3
4558 r3 = r0 + c + b + a
4560 A quadratic Beizer has the form:
4561 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4563 So equating powers of t leads to:
4564 r1 = 2/3 p1 + 1/3 p0
4565 r2 = 2/3 p1 + 1/3 p2
4566 and of course r0 = p0, r3 = p2
4569 int contour, point = 0, first_pt;
4570 FT_Outline *outline = &ft_face->glyph->outline;
4571 TTPOLYGONHEADER *pph;
4572 TTPOLYCURVE *ppc;
4573 DWORD pph_start, cpfx, type;
4574 FT_Vector cubic_control[4];
4575 if(buflen == 0) buf = NULL;
4577 if (needsTransform && buf) {
4578 pFT_Outline_Transform(outline, &transMat);
4581 for(contour = 0; contour < outline->n_contours; contour++) {
4582 pph_start = needed;
4583 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4584 first_pt = point;
4585 if(buf) {
4586 pph->dwType = TT_POLYGON_TYPE;
4587 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4589 needed += sizeof(*pph);
4590 point++;
4591 while(point <= outline->contours[contour]) {
4592 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4593 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4594 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4595 cpfx = 0;
4596 do {
4597 if(type == TT_PRIM_LINE) {
4598 if(buf)
4599 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4600 cpfx++;
4601 point++;
4602 } else {
4603 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4604 so cpfx = 3n */
4606 /* FIXME: Possible optimization in endpoint calculation
4607 if there are two consecutive curves */
4608 cubic_control[0] = outline->points[point-1];
4609 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4610 cubic_control[0].x += outline->points[point].x + 1;
4611 cubic_control[0].y += outline->points[point].y + 1;
4612 cubic_control[0].x >>= 1;
4613 cubic_control[0].y >>= 1;
4615 if(point+1 > outline->contours[contour])
4616 cubic_control[3] = outline->points[first_pt];
4617 else {
4618 cubic_control[3] = outline->points[point+1];
4619 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4620 cubic_control[3].x += outline->points[point].x + 1;
4621 cubic_control[3].y += outline->points[point].y + 1;
4622 cubic_control[3].x >>= 1;
4623 cubic_control[3].y >>= 1;
4626 /* r1 = 1/3 p0 + 2/3 p1
4627 r2 = 1/3 p2 + 2/3 p1 */
4628 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4629 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4630 cubic_control[2] = cubic_control[1];
4631 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4632 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4633 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4634 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4635 if(buf) {
4636 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4637 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4638 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4640 cpfx += 3;
4641 point++;
4643 } while(point <= outline->contours[contour] &&
4644 (outline->tags[point] & FT_Curve_Tag_On) ==
4645 (outline->tags[point-1] & FT_Curve_Tag_On));
4646 /* At the end of a contour Windows adds the start point,
4647 but only for Beziers and we've already done that.
4649 if(point <= outline->contours[contour] &&
4650 outline->tags[point] & FT_Curve_Tag_On) {
4651 /* This is the closing pt of a bezier, but we've already
4652 added it, so just inc point and carry on */
4653 point++;
4655 if(buf) {
4656 ppc->wType = type;
4657 ppc->cpfx = cpfx;
4659 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4661 if(buf)
4662 pph->cb = needed - pph_start;
4664 break;
4667 default:
4668 FIXME("Unsupported format %d\n", format);
4669 LeaveCriticalSection( &freetype_cs );
4670 return GDI_ERROR;
4672 LeaveCriticalSection( &freetype_cs );
4673 return needed;
4676 static BOOL get_bitmap_text_metrics(GdiFont *font)
4678 FT_Face ft_face = font->ft_face;
4679 #ifdef HAVE_FREETYPE_FTWINFNT_H
4680 FT_WinFNT_HeaderRec winfnt_header;
4681 #endif
4682 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4683 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4684 font->potm->otmSize = size;
4686 #define TM font->potm->otmTextMetrics
4687 #ifdef HAVE_FREETYPE_FTWINFNT_H
4688 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4690 TM.tmHeight = winfnt_header.pixel_height;
4691 TM.tmAscent = winfnt_header.ascent;
4692 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4693 TM.tmInternalLeading = winfnt_header.internal_leading;
4694 TM.tmExternalLeading = winfnt_header.external_leading;
4695 TM.tmAveCharWidth = winfnt_header.avg_width;
4696 TM.tmMaxCharWidth = winfnt_header.max_width;
4697 TM.tmWeight = winfnt_header.weight;
4698 TM.tmOverhang = 0;
4699 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4700 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4701 TM.tmFirstChar = winfnt_header.first_char;
4702 TM.tmLastChar = winfnt_header.last_char;
4703 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4704 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4705 TM.tmItalic = winfnt_header.italic;
4706 TM.tmUnderlined = font->underline;
4707 TM.tmStruckOut = font->strikeout;
4708 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4709 TM.tmCharSet = winfnt_header.charset;
4711 else
4712 #endif
4714 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4715 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4716 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4717 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4718 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4719 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4720 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4721 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4722 TM.tmOverhang = 0;
4723 TM.tmDigitizedAspectX = 96; /* FIXME */
4724 TM.tmDigitizedAspectY = 96; /* FIXME */
4725 TM.tmFirstChar = 1;
4726 TM.tmLastChar = 255;
4727 TM.tmDefaultChar = 32;
4728 TM.tmBreakChar = 32;
4729 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4730 TM.tmUnderlined = font->underline;
4731 TM.tmStruckOut = font->strikeout;
4732 /* NB inverted meaning of TMPF_FIXED_PITCH */
4733 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4734 TM.tmCharSet = font->charset;
4736 #undef TM
4738 return TRUE;
4742 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4744 float scale_x;
4746 if (font->aveWidth)
4748 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4749 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4751 else
4752 scale_x = font->scale_y;
4754 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4755 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4756 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4757 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4758 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4760 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4761 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4764 /*************************************************************
4765 * WineEngGetTextMetrics
4768 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4770 EnterCriticalSection( &freetype_cs );
4771 if(!font->potm) {
4772 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4773 if(!get_bitmap_text_metrics(font))
4775 LeaveCriticalSection( &freetype_cs );
4776 return FALSE;
4779 if(!font->potm)
4781 LeaveCriticalSection( &freetype_cs );
4782 return FALSE;
4784 *ptm = font->potm->otmTextMetrics;
4785 scale_font_metrics(font, ptm);
4786 LeaveCriticalSection( &freetype_cs );
4787 return TRUE;
4791 /*************************************************************
4792 * WineEngGetOutlineTextMetrics
4795 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4796 OUTLINETEXTMETRICW *potm)
4798 FT_Face ft_face = font->ft_face;
4799 UINT needed, lenfam, lensty, ret;
4800 TT_OS2 *pOS2;
4801 TT_HoriHeader *pHori;
4802 TT_Postscript *pPost;
4803 FT_Fixed x_scale, y_scale;
4804 WCHAR *family_nameW, *style_nameW;
4805 static const WCHAR spaceW[] = {' ', '\0'};
4806 char *cp;
4807 INT ascent, descent;
4809 TRACE("font=%p\n", font);
4811 if(!FT_IS_SCALABLE(ft_face))
4812 return 0;
4814 EnterCriticalSection( &freetype_cs );
4816 if(font->potm) {
4817 if(cbSize >= font->potm->otmSize)
4819 memcpy(potm, font->potm, font->potm->otmSize);
4820 scale_font_metrics(font, &potm->otmTextMetrics);
4822 LeaveCriticalSection( &freetype_cs );
4823 return font->potm->otmSize;
4827 needed = sizeof(*potm);
4829 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4830 family_nameW = strdupW(font->name);
4832 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4833 * sizeof(WCHAR);
4834 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4835 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4836 style_nameW, lensty/sizeof(WCHAR));
4838 /* These names should be read from the TT name table */
4840 /* length of otmpFamilyName */
4841 needed += lenfam;
4843 /* length of otmpFaceName */
4844 if(!strcasecmp(ft_face->style_name, "regular")) {
4845 needed += lenfam; /* just the family name */
4846 } else {
4847 needed += lenfam + lensty; /* family + " " + style */
4850 /* length of otmpStyleName */
4851 needed += lensty;
4853 /* length of otmpFullName */
4854 needed += lenfam + lensty;
4857 x_scale = ft_face->size->metrics.x_scale;
4858 y_scale = ft_face->size->metrics.y_scale;
4860 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4861 if(!pOS2) {
4862 FIXME("Can't find OS/2 table - not TT font?\n");
4863 ret = 0;
4864 goto end;
4867 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4868 if(!pHori) {
4869 FIXME("Can't find HHEA table - not TT font?\n");
4870 ret = 0;
4871 goto end;
4874 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4876 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",
4877 pOS2->usWinAscent, pOS2->usWinDescent,
4878 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4879 ft_face->ascender, ft_face->descender, ft_face->height,
4880 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4881 ft_face->bbox.yMax, ft_face->bbox.yMin);
4883 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4884 font->potm->otmSize = needed;
4886 #define TM font->potm->otmTextMetrics
4888 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4889 ascent = pHori->Ascender;
4890 descent = -pHori->Descender;
4891 } else {
4892 ascent = pOS2->usWinAscent;
4893 descent = pOS2->usWinDescent;
4896 if(font->yMax) {
4897 TM.tmAscent = font->yMax;
4898 TM.tmDescent = -font->yMin;
4899 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4900 } else {
4901 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4902 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4903 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4904 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4907 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4909 /* MSDN says:
4910 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4912 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4913 ((ascent + descent) -
4914 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4916 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4917 if (TM.tmAveCharWidth == 0) {
4918 TM.tmAveCharWidth = 1;
4920 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4921 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4922 TM.tmOverhang = 0;
4923 TM.tmDigitizedAspectX = 300;
4924 TM.tmDigitizedAspectY = 300;
4925 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4926 * symbol range to 0 - f0ff
4928 if (font->charset == SYMBOL_CHARSET)
4929 TM.tmFirstChar = 0;
4930 else
4931 TM.tmFirstChar = pOS2->usFirstCharIndex;
4932 TM.tmLastChar = pOS2->usLastCharIndex;
4933 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4934 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4935 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4936 TM.tmUnderlined = font->underline;
4937 TM.tmStruckOut = font->strikeout;
4939 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4940 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4941 (pOS2->version == 0xFFFFU ||
4942 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4943 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4944 else
4945 TM.tmPitchAndFamily = 0;
4947 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4948 case PAN_FAMILY_SCRIPT:
4949 TM.tmPitchAndFamily |= FF_SCRIPT;
4950 break;
4951 case PAN_FAMILY_DECORATIVE:
4952 case PAN_FAMILY_PICTORIAL:
4953 TM.tmPitchAndFamily |= FF_DECORATIVE;
4954 break;
4955 case PAN_FAMILY_TEXT_DISPLAY:
4956 if(TM.tmPitchAndFamily == 0) /* fixed */
4957 TM.tmPitchAndFamily = FF_MODERN;
4958 else {
4959 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4960 case PAN_SERIF_NORMAL_SANS:
4961 case PAN_SERIF_OBTUSE_SANS:
4962 case PAN_SERIF_PERP_SANS:
4963 TM.tmPitchAndFamily |= FF_SWISS;
4964 break;
4965 default:
4966 TM.tmPitchAndFamily |= FF_ROMAN;
4969 break;
4970 default:
4971 TM.tmPitchAndFamily |= FF_DONTCARE;
4974 if(FT_IS_SCALABLE(ft_face))
4975 TM.tmPitchAndFamily |= TMPF_VECTOR;
4977 if(FT_IS_SFNT(ft_face))
4979 if (font->ntmFlags & NTM_PS_OPENTYPE)
4980 TM.tmPitchAndFamily |= TMPF_DEVICE;
4981 else
4982 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4985 TM.tmCharSet = font->charset;
4986 #undef TM
4988 font->potm->otmFiller = 0;
4989 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4990 font->potm->otmfsSelection = pOS2->fsSelection;
4991 font->potm->otmfsType = pOS2->fsType;
4992 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4993 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4994 font->potm->otmItalicAngle = 0; /* POST table */
4995 font->potm->otmEMSquare = ft_face->units_per_EM;
4996 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4997 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4998 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4999 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5000 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5001 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5002 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5003 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5004 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5005 font->potm->otmMacAscent = 0; /* where do these come from ? */
5006 font->potm->otmMacDescent = 0;
5007 font->potm->otmMacLineGap = 0;
5008 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5009 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5010 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5011 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5012 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5013 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5014 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5015 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5016 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5017 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5018 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5019 if(!pPost) {
5020 font->potm->otmsUnderscoreSize = 0;
5021 font->potm->otmsUnderscorePosition = 0;
5022 } else {
5023 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5024 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5027 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5028 cp = (char*)font->potm + sizeof(*font->potm);
5029 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5030 strcpyW((WCHAR*)cp, family_nameW);
5031 cp += lenfam;
5032 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5033 strcpyW((WCHAR*)cp, style_nameW);
5034 cp += lensty;
5035 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5036 strcpyW((WCHAR*)cp, family_nameW);
5037 if(strcasecmp(ft_face->style_name, "regular")) {
5038 strcatW((WCHAR*)cp, spaceW);
5039 strcatW((WCHAR*)cp, style_nameW);
5040 cp += lenfam + lensty;
5041 } else
5042 cp += lenfam;
5043 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5044 strcpyW((WCHAR*)cp, family_nameW);
5045 strcatW((WCHAR*)cp, spaceW);
5046 strcatW((WCHAR*)cp, style_nameW);
5047 ret = needed;
5049 if(potm && needed <= cbSize)
5051 memcpy(potm, font->potm, font->potm->otmSize);
5052 scale_font_metrics(font, &potm->otmTextMetrics);
5055 end:
5056 HeapFree(GetProcessHeap(), 0, style_nameW);
5057 HeapFree(GetProcessHeap(), 0, family_nameW);
5059 LeaveCriticalSection( &freetype_cs );
5060 return ret;
5063 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5065 HFONTLIST *hfontlist;
5066 child->font = alloc_font();
5067 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5068 if(!child->font->ft_face)
5070 free_font(child->font);
5071 child->font = NULL;
5072 return FALSE;
5075 child->font->ntmFlags = child->face->ntmFlags;
5076 child->font->orientation = font->orientation;
5077 child->font->scale_y = font->scale_y;
5078 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5079 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5080 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5081 child->font->base_font = font;
5082 list_add_head(&child_font_list, &child->font->entry);
5083 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5084 return TRUE;
5087 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5089 FT_UInt g;
5090 CHILD_FONT *child_font;
5092 if(font->base_font)
5093 font = font->base_font;
5095 *linked_font = font;
5097 if((*glyph = get_glyph_index(font, c)))
5098 return TRUE;
5100 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5102 if(!child_font->font)
5103 if(!load_child_font(font, child_font))
5104 continue;
5106 if(!child_font->font->ft_face)
5107 continue;
5108 g = get_glyph_index(child_font->font, c);
5109 if(g)
5111 *glyph = g;
5112 *linked_font = child_font->font;
5113 return TRUE;
5116 return FALSE;
5119 /*************************************************************
5120 * WineEngGetCharWidth
5123 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5124 LPINT buffer)
5126 UINT c;
5127 GLYPHMETRICS gm;
5128 FT_UInt glyph_index;
5129 GdiFont *linked_font;
5131 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5133 EnterCriticalSection( &freetype_cs );
5134 for(c = firstChar; c <= lastChar; c++) {
5135 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5136 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5137 &gm, 0, NULL, NULL);
5138 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5140 LeaveCriticalSection( &freetype_cs );
5141 return TRUE;
5144 /*************************************************************
5145 * WineEngGetCharABCWidths
5148 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5149 LPABC buffer)
5151 UINT c;
5152 GLYPHMETRICS gm;
5153 FT_UInt glyph_index;
5154 GdiFont *linked_font;
5156 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5158 if(!FT_IS_SCALABLE(font->ft_face))
5159 return FALSE;
5161 EnterCriticalSection( &freetype_cs );
5163 for(c = firstChar; c <= lastChar; c++) {
5164 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5165 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5166 &gm, 0, NULL, NULL);
5167 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5168 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5169 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5170 FONT_GM(linked_font,glyph_index)->bbx;
5172 LeaveCriticalSection( &freetype_cs );
5173 return TRUE;
5176 /*************************************************************
5177 * WineEngGetCharABCWidthsI
5180 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5181 LPABC buffer)
5183 UINT c;
5184 GLYPHMETRICS gm;
5185 FT_UInt glyph_index;
5186 GdiFont *linked_font;
5188 if(!FT_HAS_HORIZONTAL(font->ft_face))
5189 return FALSE;
5191 EnterCriticalSection( &freetype_cs );
5193 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5194 if (!pgi)
5195 for(c = firstChar; c < firstChar+count; c++) {
5196 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5197 &gm, 0, NULL, NULL);
5198 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5199 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5200 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5201 - FONT_GM(linked_font,c)->bbx;
5203 else
5204 for(c = 0; c < count; c++) {
5205 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5206 &gm, 0, NULL, NULL);
5207 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5208 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5209 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5210 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5213 LeaveCriticalSection( &freetype_cs );
5214 return TRUE;
5217 /*************************************************************
5218 * WineEngGetTextExtentExPoint
5221 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5222 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5224 INT idx;
5225 INT nfit = 0, ext;
5226 GLYPHMETRICS gm;
5227 TEXTMETRICW tm;
5228 FT_UInt glyph_index;
5229 GdiFont *linked_font;
5231 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5232 max_ext, size);
5234 EnterCriticalSection( &freetype_cs );
5236 size->cx = 0;
5237 WineEngGetTextMetrics(font, &tm);
5238 size->cy = tm.tmHeight;
5240 for(idx = 0; idx < count; idx++) {
5241 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5242 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5243 &gm, 0, NULL, NULL);
5244 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5245 ext = size->cx;
5246 if (! pnfit || ext <= max_ext) {
5247 ++nfit;
5248 if (dxs)
5249 dxs[idx] = ext;
5253 if (pnfit)
5254 *pnfit = nfit;
5256 LeaveCriticalSection( &freetype_cs );
5257 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5258 return TRUE;
5261 /*************************************************************
5262 * WineEngGetTextExtentExPointI
5265 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5266 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5268 INT idx;
5269 INT nfit = 0, ext;
5270 GLYPHMETRICS gm;
5271 TEXTMETRICW tm;
5273 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5275 EnterCriticalSection( &freetype_cs );
5277 size->cx = 0;
5278 WineEngGetTextMetrics(font, &tm);
5279 size->cy = tm.tmHeight;
5281 for(idx = 0; idx < count; idx++) {
5282 WineEngGetGlyphOutline(font, indices[idx],
5283 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5284 NULL);
5285 size->cx += FONT_GM(font,indices[idx])->adv;
5286 ext = size->cx;
5287 if (! pnfit || ext <= max_ext) {
5288 ++nfit;
5289 if (dxs)
5290 dxs[idx] = ext;
5294 if (pnfit)
5295 *pnfit = nfit;
5297 LeaveCriticalSection( &freetype_cs );
5298 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5299 return TRUE;
5302 /*************************************************************
5303 * WineEngGetFontData
5306 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5307 DWORD cbData)
5309 FT_Face ft_face = font->ft_face;
5310 FT_ULong len;
5311 FT_Error err;
5313 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5314 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5315 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5317 if(!FT_IS_SFNT(ft_face))
5318 return GDI_ERROR;
5320 if(!buf || !cbData)
5321 len = 0;
5322 else
5323 len = cbData;
5325 if(table) { /* MS tags differ in endianness from FT ones */
5326 table = table >> 24 | table << 24 |
5327 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5330 /* make sure value of len is the value freetype says it needs */
5331 if(buf && len)
5333 FT_ULong needed = 0;
5334 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5335 if( !err && needed < len) len = needed;
5337 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5339 if(err) {
5340 TRACE("Can't find table %c%c%c%c\n",
5341 /* bytes were reversed */
5342 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5343 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5344 return GDI_ERROR;
5346 return len;
5349 /*************************************************************
5350 * WineEngGetTextFace
5353 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5355 if(str) {
5356 lstrcpynW(str, font->name, count);
5357 return strlenW(font->name);
5358 } else
5359 return strlenW(font->name) + 1;
5362 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5364 if (fs) *fs = font->fs;
5365 return font->charset;
5368 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5370 GdiFont *font = dc->gdiFont, *linked_font;
5371 struct list *first_hfont;
5372 BOOL ret;
5374 EnterCriticalSection( &freetype_cs );
5375 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5376 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5377 if(font == linked_font)
5378 *new_hfont = dc->hFont;
5379 else
5381 first_hfont = list_head(&linked_font->hfontlist);
5382 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5384 LeaveCriticalSection( &freetype_cs );
5385 return ret;
5388 /* Retrieve a list of supported Unicode ranges for a given font.
5389 * Can be called with NULL gs to calculate the buffer size. Returns
5390 * the number of ranges found.
5392 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5394 DWORD num_ranges = 0;
5396 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5398 FT_UInt glyph_code;
5399 FT_ULong char_code, char_code_prev;
5401 glyph_code = 0;
5402 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5404 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5405 face->num_glyphs, glyph_code, char_code);
5407 if (!glyph_code) return 0;
5409 if (gs)
5411 gs->ranges[0].wcLow = (USHORT)char_code;
5412 gs->ranges[0].cGlyphs = 0;
5413 gs->cGlyphsSupported = 0;
5416 num_ranges = 1;
5417 while (glyph_code)
5419 if (char_code < char_code_prev)
5421 ERR("expected increasing char code from FT_Get_Next_Char\n");
5422 return 0;
5424 if (char_code - char_code_prev > 1)
5426 num_ranges++;
5427 if (gs)
5429 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5430 gs->ranges[num_ranges - 1].cGlyphs = 1;
5431 gs->cGlyphsSupported++;
5434 else if (gs)
5436 gs->ranges[num_ranges - 1].cGlyphs++;
5437 gs->cGlyphsSupported++;
5439 char_code_prev = char_code;
5440 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5443 else
5444 FIXME("encoding %u not supported\n", face->charmap->encoding);
5446 return num_ranges;
5449 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5451 DWORD size = 0;
5452 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5454 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5455 if (glyphset)
5457 glyphset->cbThis = size;
5458 glyphset->cRanges = num_ranges;
5460 return size;
5463 /*************************************************************
5464 * FontIsLinked
5466 BOOL WineEngFontIsLinked(GdiFont *font)
5468 BOOL ret;
5469 EnterCriticalSection( &freetype_cs );
5470 ret = !list_empty(&font->child_fonts);
5471 LeaveCriticalSection( &freetype_cs );
5472 return ret;
5475 static BOOL is_hinting_enabled(void)
5477 /* Use the >= 2.2.0 function if available */
5478 if(pFT_Get_TrueType_Engine_Type)
5480 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5481 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5483 #ifdef FT_DRIVER_HAS_HINTER
5484 else
5486 FT_Module mod;
5488 /* otherwise if we've been compiled with < 2.2.0 headers
5489 use the internal macro */
5490 mod = pFT_Get_Module(library, "truetype");
5491 if(mod && FT_DRIVER_HAS_HINTER(mod))
5492 return TRUE;
5494 #endif
5496 return FALSE;
5499 /*************************************************************************
5500 * GetRasterizerCaps (GDI32.@)
5502 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5504 static int hinting = -1;
5506 if(hinting == -1)
5508 hinting = is_hinting_enabled();
5509 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5512 lprs->nSize = sizeof(RASTERIZER_STATUS);
5513 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5514 lprs->nLanguageID = 0;
5515 return TRUE;
5518 /*************************************************************************
5519 * Kerning support for TrueType fonts
5521 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5523 struct TT_kern_table
5525 USHORT version;
5526 USHORT nTables;
5529 struct TT_kern_subtable
5531 USHORT version;
5532 USHORT length;
5533 union
5535 USHORT word;
5536 struct
5538 USHORT horizontal : 1;
5539 USHORT minimum : 1;
5540 USHORT cross_stream: 1;
5541 USHORT override : 1;
5542 USHORT reserved1 : 4;
5543 USHORT format : 8;
5544 } bits;
5545 } coverage;
5548 struct TT_format0_kern_subtable
5550 USHORT nPairs;
5551 USHORT searchRange;
5552 USHORT entrySelector;
5553 USHORT rangeShift;
5556 struct TT_kern_pair
5558 USHORT left;
5559 USHORT right;
5560 short value;
5563 static DWORD parse_format0_kern_subtable(GdiFont *font,
5564 const struct TT_format0_kern_subtable *tt_f0_ks,
5565 const USHORT *glyph_to_char,
5566 KERNINGPAIR *kern_pair, DWORD cPairs)
5568 USHORT i, nPairs;
5569 const struct TT_kern_pair *tt_kern_pair;
5571 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5573 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5575 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5576 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5577 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5579 if (!kern_pair || !cPairs)
5580 return nPairs;
5582 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5584 nPairs = min(nPairs, cPairs);
5586 for (i = 0; i < nPairs; i++)
5588 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5589 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5590 /* this algorithm appears to better match what Windows does */
5591 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5592 if (kern_pair->iKernAmount < 0)
5594 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5595 kern_pair->iKernAmount -= font->ppem;
5597 else if (kern_pair->iKernAmount > 0)
5599 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5600 kern_pair->iKernAmount += font->ppem;
5602 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5604 TRACE("left %u right %u value %d\n",
5605 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5607 kern_pair++;
5609 TRACE("copied %u entries\n", nPairs);
5610 return nPairs;
5613 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5615 DWORD length;
5616 void *buf;
5617 const struct TT_kern_table *tt_kern_table;
5618 const struct TT_kern_subtable *tt_kern_subtable;
5619 USHORT i, nTables;
5620 USHORT *glyph_to_char;
5622 EnterCriticalSection( &freetype_cs );
5623 if (font->total_kern_pairs != (DWORD)-1)
5625 if (cPairs && kern_pair)
5627 cPairs = min(cPairs, font->total_kern_pairs);
5628 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5629 LeaveCriticalSection( &freetype_cs );
5630 return cPairs;
5632 LeaveCriticalSection( &freetype_cs );
5633 return font->total_kern_pairs;
5636 font->total_kern_pairs = 0;
5638 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5640 if (length == GDI_ERROR)
5642 TRACE("no kerning data in the font\n");
5643 LeaveCriticalSection( &freetype_cs );
5644 return 0;
5647 buf = HeapAlloc(GetProcessHeap(), 0, length);
5648 if (!buf)
5650 WARN("Out of memory\n");
5651 LeaveCriticalSection( &freetype_cs );
5652 return 0;
5655 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5657 /* build a glyph index to char code map */
5658 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5659 if (!glyph_to_char)
5661 WARN("Out of memory allocating a glyph index to char code map\n");
5662 HeapFree(GetProcessHeap(), 0, buf);
5663 LeaveCriticalSection( &freetype_cs );
5664 return 0;
5667 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5669 FT_UInt glyph_code;
5670 FT_ULong char_code;
5672 glyph_code = 0;
5673 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5675 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5676 font->ft_face->num_glyphs, glyph_code, char_code);
5678 while (glyph_code)
5680 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5682 /* FIXME: This doesn't match what Windows does: it does some fancy
5683 * things with duplicate glyph index to char code mappings, while
5684 * we just avoid overriding existing entries.
5686 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5687 glyph_to_char[glyph_code] = (USHORT)char_code;
5689 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5692 else
5694 ULONG n;
5696 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5697 for (n = 0; n <= 65535; n++)
5698 glyph_to_char[n] = (USHORT)n;
5701 tt_kern_table = buf;
5702 nTables = GET_BE_WORD(tt_kern_table->nTables);
5703 TRACE("version %u, nTables %u\n",
5704 GET_BE_WORD(tt_kern_table->version), nTables);
5706 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5708 for (i = 0; i < nTables; i++)
5710 struct TT_kern_subtable tt_kern_subtable_copy;
5712 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5713 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5714 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5716 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5717 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5718 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5720 /* According to the TrueType specification this is the only format
5721 * that will be properly interpreted by Windows and OS/2
5723 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5725 DWORD new_chunk, old_total = font->total_kern_pairs;
5727 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5728 glyph_to_char, NULL, 0);
5729 font->total_kern_pairs += new_chunk;
5731 if (!font->kern_pairs)
5732 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5733 font->total_kern_pairs * sizeof(*font->kern_pairs));
5734 else
5735 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5736 font->total_kern_pairs * sizeof(*font->kern_pairs));
5738 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5739 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5741 else
5742 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5744 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5747 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5748 HeapFree(GetProcessHeap(), 0, buf);
5750 if (cPairs && kern_pair)
5752 cPairs = min(cPairs, font->total_kern_pairs);
5753 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5754 LeaveCriticalSection( &freetype_cs );
5755 return cPairs;
5757 LeaveCriticalSection( &freetype_cs );
5758 return font->total_kern_pairs;
5761 #else /* HAVE_FREETYPE */
5763 /*************************************************************************/
5765 BOOL WineEngInit(void)
5767 return FALSE;
5769 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5771 return NULL;
5773 BOOL WineEngDestroyFontInstance(HFONT hfont)
5775 return FALSE;
5778 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5780 return 1;
5783 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5784 LPWORD pgi, DWORD flags)
5786 return GDI_ERROR;
5789 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5790 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5791 const MAT2* lpmat)
5793 ERR("called but we don't have FreeType\n");
5794 return GDI_ERROR;
5797 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5799 ERR("called but we don't have FreeType\n");
5800 return FALSE;
5803 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5804 OUTLINETEXTMETRICW *potm)
5806 ERR("called but we don't have FreeType\n");
5807 return 0;
5810 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5811 LPINT buffer)
5813 ERR("called but we don't have FreeType\n");
5814 return FALSE;
5817 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5818 LPABC buffer)
5820 ERR("called but we don't have FreeType\n");
5821 return FALSE;
5824 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5825 LPABC buffer)
5827 ERR("called but we don't have FreeType\n");
5828 return FALSE;
5831 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5832 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5834 ERR("called but we don't have FreeType\n");
5835 return FALSE;
5838 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5839 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5841 ERR("called but we don't have FreeType\n");
5842 return FALSE;
5845 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5846 DWORD cbData)
5848 ERR("called but we don't have FreeType\n");
5849 return GDI_ERROR;
5852 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5854 ERR("called but we don't have FreeType\n");
5855 return 0;
5858 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5860 FIXME(":stub\n");
5861 return 1;
5864 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5866 FIXME(":stub\n");
5867 return TRUE;
5870 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5872 FIXME(":stub\n");
5873 return NULL;
5876 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5878 FIXME(":stub\n");
5879 return DEFAULT_CHARSET;
5882 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5884 return FALSE;
5887 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5889 FIXME("(%p, %p): stub\n", font, glyphset);
5890 return 0;
5893 BOOL WineEngFontIsLinked(GdiFont *font)
5895 return FALSE;
5898 /*************************************************************************
5899 * GetRasterizerCaps (GDI32.@)
5901 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5903 lprs->nSize = sizeof(RASTERIZER_STATUS);
5904 lprs->wFlags = 0;
5905 lprs->nLanguageID = 0;
5906 return TRUE;
5909 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5911 ERR("called but we don't have FreeType\n");
5912 return 0;
5915 #endif /* HAVE_FREETYPE */