gdi32: Extend the font substitution test, make it pass under Wine.
[wine.git] / dlls / gdi32 / freetype.c
blobdddfb6a8a922fe2c4e641e9d812f80ea7568d557
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
200 #undef MAKE_FUNCPTR
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
227 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229 FT_Short height;
230 FT_Short width;
231 FT_Pos size;
232 FT_Pos x_ppem;
233 FT_Pos y_ppem;
234 FT_Short internal_leading;
235 } Bitmap_Size;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
240 typedef struct {
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
245 struct enum_data
247 ENUMLOGFONTEXW elf;
248 NEWTEXTMETRICEXW ntm;
249 DWORD type;
252 typedef struct tagFace {
253 struct list entry;
254 WCHAR *StyleName;
255 char *file;
256 void *font_data_ptr;
257 DWORD font_data_size;
258 FT_Long face_index;
259 FONTSIGNATURE fs;
260 FONTSIGNATURE fs_links;
261 DWORD ntmFlags;
262 FT_Fixed font_version;
263 BOOL scalable;
264 Bitmap_Size size; /* set if face is a bitmap */
265 BOOL external; /* TRUE if we should manually add this font to the registry */
266 struct tagFamily *family;
267 /* Cached data for Enum */
268 struct enum_data *cached_enum_data;
269 } Face;
271 typedef struct tagFamily {
272 struct list entry;
273 const WCHAR *FamilyName;
274 struct list faces;
275 } Family;
277 typedef struct {
278 GLYPHMETRICS gm;
279 INT adv; /* These three hold to widths of the unrotated chars */
280 INT lsb;
281 INT bbx;
282 BOOL init;
283 } GM;
285 typedef struct {
286 FLOAT eM11, eM12;
287 FLOAT eM21, eM22;
288 } FMAT2;
290 typedef struct {
291 DWORD hash;
292 LOGFONTW lf;
293 FMAT2 matrix;
294 BOOL can_use_bitmap;
295 } FONT_DESC;
297 typedef struct tagHFONTLIST {
298 struct list entry;
299 HFONT hfont;
300 } HFONTLIST;
302 typedef struct {
303 struct list entry;
304 Face *face;
305 GdiFont *font;
306 } CHILD_FONT;
308 struct tagGdiFont {
309 struct list entry;
310 GM **gm;
311 DWORD gmsize;
312 struct list hfontlist;
313 OUTLINETEXTMETRICW *potm;
314 DWORD total_kern_pairs;
315 KERNINGPAIR *kern_pairs;
316 struct list child_fonts;
318 /* the following members can be accessed without locking, they are never modified after creation */
319 FT_Face ft_face;
320 struct font_mapping *mapping;
321 LPWSTR name;
322 int charset;
323 int codepage;
324 BOOL fake_italic;
325 BOOL fake_bold;
326 BYTE underline;
327 BYTE strikeout;
328 INT orientation;
329 FONT_DESC font_desc;
330 LONG aveWidth, ppem;
331 float scale_y;
332 SHORT yMax;
333 SHORT yMin;
334 DWORD ntmFlags;
335 FONTSIGNATURE fs;
336 GdiFont *base_font;
337 VOID *GSUB_Table;
340 typedef struct {
341 struct list entry;
342 const WCHAR *font_name;
343 struct list links;
344 } SYSTEM_LINKS;
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
350 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list = LIST_INIT(child_font_list);
353 static struct list system_links = LIST_INIT(system_links);
355 static struct list font_subst_list = LIST_INIT(font_subst_list);
357 static struct list font_list = LIST_INIT(font_list);
359 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
364 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
365 'W','i','n','d','o','w','s','\\',
366 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
367 'F','o','n','t','s','\0'};
369 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s',' ','N','T','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
375 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
376 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
377 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
379 static const WCHAR * const SystemFontValues[4] = {
380 System_Value,
381 OEMFont_Value,
382 FixedSys_Value,
383 NULL
386 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
387 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
389 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
390 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
391 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
392 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
393 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
394 'E','u','r','o','p','e','a','n','\0'};
395 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
396 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
397 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
398 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
399 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
400 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
401 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
402 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
403 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
404 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
405 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
406 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
408 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
409 WesternW, /*00*/
410 Central_EuropeanW,
411 CyrillicW,
412 GreekW,
413 TurkishW,
414 HebrewW,
415 ArabicW,
416 BalticW,
417 VietnameseW, /*08*/
418 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
419 ThaiW,
420 JapaneseW,
421 CHINESE_GB2312W,
422 HangulW,
423 CHINESE_BIG5W,
424 Hangul_Johab_W,
425 NULL, NULL, /*23*/
426 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
427 SymbolW /*31*/
430 typedef struct {
431 WCHAR *name;
432 INT charset;
433 } NameCs;
435 typedef struct tagFontSubst {
436 struct list entry;
437 NameCs from;
438 NameCs to;
439 } FontSubst;
441 struct font_mapping
443 struct list entry;
444 int refcount;
445 dev_t dev;
446 ino_t ino;
447 void *data;
448 size_t size;
451 static struct list mappings_list = LIST_INIT( mappings_list );
453 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
455 static CRITICAL_SECTION freetype_cs;
456 static CRITICAL_SECTION_DEBUG critsect_debug =
458 0, 0, &freetype_cs,
459 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
460 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
462 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
464 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
466 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
467 static BOOL use_default_fallback = FALSE;
469 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
471 /****************************************
472 * Notes on .fon files
474 * The fonts System, FixedSys and Terminal are special. There are typically multiple
475 * versions installed for different resolutions and codepages. Windows stores which one to use
476 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
477 * Key Meaning
478 * FIXEDFON.FON FixedSys
479 * FONTS.FON System
480 * OEMFONT.FON Terminal
481 * LogPixels Current dpi set by the display control panel applet
482 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
483 * also has a LogPixels value that appears to mirror this)
485 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
486 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
487 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
488 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
489 * so that makes sense.
491 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
492 * to be mapped into the registry on Windows 2000 at least).
493 * I have
494 * woafont=app850.fon
495 * ega80woa.fon=ega80850.fon
496 * ega40woa.fon=ega40850.fon
497 * cga80woa.fon=cga80850.fon
498 * cga40woa.fon=cga40850.fon
501 /* These are all structures needed for the GSUB table */
503 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
504 #define TATEGAKI_LOWER_BOUND 0x02F1
506 typedef struct {
507 DWORD version;
508 WORD ScriptList;
509 WORD FeatureList;
510 WORD LookupList;
511 } GSUB_Header;
513 typedef struct {
514 CHAR ScriptTag[4];
515 WORD Script;
516 } GSUB_ScriptRecord;
518 typedef struct {
519 WORD ScriptCount;
520 GSUB_ScriptRecord ScriptRecord[1];
521 } GSUB_ScriptList;
523 typedef struct {
524 CHAR LangSysTag[4];
525 WORD LangSys;
526 } GSUB_LangSysRecord;
528 typedef struct {
529 WORD DefaultLangSys;
530 WORD LangSysCount;
531 GSUB_LangSysRecord LangSysRecord[1];
532 } GSUB_Script;
534 typedef struct {
535 WORD LookupOrder; /* Reserved */
536 WORD ReqFeatureIndex;
537 WORD FeatureCount;
538 WORD FeatureIndex[1];
539 } GSUB_LangSys;
541 typedef struct {
542 CHAR FeatureTag[4];
543 WORD Feature;
544 } GSUB_FeatureRecord;
546 typedef struct {
547 WORD FeatureCount;
548 GSUB_FeatureRecord FeatureRecord[1];
549 } GSUB_FeatureList;
551 typedef struct {
552 WORD FeatureParams; /* Reserved */
553 WORD LookupCount;
554 WORD LookupListIndex[1];
555 } GSUB_Feature;
557 typedef struct {
558 WORD LookupCount;
559 WORD Lookup[1];
560 } GSUB_LookupList;
562 typedef struct {
563 WORD LookupType;
564 WORD LookupFlag;
565 WORD SubTableCount;
566 WORD SubTable[1];
567 } GSUB_LookupTable;
569 typedef struct {
570 WORD CoverageFormat;
571 WORD GlyphCount;
572 WORD GlyphArray[1];
573 } GSUB_CoverageFormat1;
575 typedef struct {
576 WORD Start;
577 WORD End;
578 WORD StartCoverageIndex;
579 } GSUB_RangeRecord;
581 typedef struct {
582 WORD CoverageFormat;
583 WORD RangeCount;
584 GSUB_RangeRecord RangeRecord[1];
585 } GSUB_CoverageFormat2;
587 typedef struct {
588 WORD SubstFormat; /* = 1 */
589 WORD Coverage;
590 WORD DeltaGlyphID;
591 } GSUB_SingleSubstFormat1;
593 typedef struct {
594 WORD SubstFormat; /* = 2 */
595 WORD Coverage;
596 WORD GlyphCount;
597 WORD Substitute[1];
598 }GSUB_SingleSubstFormat2;
600 #ifdef HAVE_CARBON_CARBON_H
601 static char *find_cache_dir(void)
603 FSRef ref;
604 OSErr err;
605 static char cached_path[MAX_PATH];
606 static const char *wine = "/Wine", *fonts = "/Fonts";
608 if(*cached_path) return cached_path;
610 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
611 if(err != noErr)
613 WARN("can't create cached data folder\n");
614 return NULL;
616 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
617 if(err != noErr)
619 WARN("can't create cached data path\n");
620 *cached_path = '\0';
621 return NULL;
623 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
625 ERR("Could not create full path\n");
626 *cached_path = '\0';
627 return NULL;
629 strcat(cached_path, wine);
631 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
633 WARN("Couldn't mkdir %s\n", cached_path);
634 *cached_path = '\0';
635 return NULL;
637 strcat(cached_path, fonts);
638 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
640 WARN("Couldn't mkdir %s\n", cached_path);
641 *cached_path = '\0';
642 return NULL;
644 return cached_path;
647 /******************************************************************
648 * expand_mac_font
650 * Extracts individual TrueType font files from a Mac suitcase font
651 * and saves them into the user's caches directory (see
652 * find_cache_dir()).
653 * Returns a NULL terminated array of filenames.
655 * We do this because they are apps that try to read ttf files
656 * themselves and they don't like Mac suitcase files.
658 static char **expand_mac_font(const char *path)
660 FSRef ref;
661 SInt16 res_ref;
662 OSStatus s;
663 unsigned int idx;
664 const char *out_dir;
665 const char *filename;
666 int output_len;
667 struct {
668 char **array;
669 unsigned int size, max_size;
670 } ret;
672 TRACE("path %s\n", path);
674 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
675 if(s != noErr)
677 WARN("failed to get ref\n");
678 return NULL;
681 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
682 if(s != noErr)
684 TRACE("no data fork, so trying resource fork\n");
685 res_ref = FSOpenResFile(&ref, fsRdPerm);
686 if(res_ref == -1)
688 TRACE("unable to open resource fork\n");
689 return NULL;
693 ret.size = 0;
694 ret.max_size = 10;
695 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
696 if(!ret.array)
698 CloseResFile(res_ref);
699 return NULL;
702 out_dir = find_cache_dir();
704 filename = strrchr(path, '/');
705 if(!filename) filename = path;
706 else filename++;
708 /* output filename has the form out_dir/filename_%04x.ttf */
709 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
711 UseResFile(res_ref);
712 idx = 1;
713 while(1)
715 FamRec *fam_rec;
716 unsigned short *num_faces_ptr, num_faces, face;
717 AsscEntry *assoc;
718 Handle fond;
719 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
721 fond = Get1IndResource(fond_res, idx);
722 if(!fond) break;
723 TRACE("got fond resource %d\n", idx);
724 HLock(fond);
726 fam_rec = *(FamRec**)fond;
727 num_faces_ptr = (unsigned short *)(fam_rec + 1);
728 num_faces = GET_BE_WORD(*num_faces_ptr);
729 num_faces++;
730 assoc = (AsscEntry*)(num_faces_ptr + 1);
731 TRACE("num faces %04x\n", num_faces);
732 for(face = 0; face < num_faces; face++, assoc++)
734 Handle sfnt;
735 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
736 unsigned short size, font_id;
737 char *output;
739 size = GET_BE_WORD(assoc->fontSize);
740 font_id = GET_BE_WORD(assoc->fontID);
741 if(size != 0)
743 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
744 continue;
747 TRACE("trying to load sfnt id %04x\n", font_id);
748 sfnt = GetResource(sfnt_res, font_id);
749 if(!sfnt)
751 TRACE("can't get sfnt resource %04x\n", font_id);
752 continue;
755 output = HeapAlloc(GetProcessHeap(), 0, output_len);
756 if(output)
758 int fd;
760 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
762 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
763 if(fd != -1 || errno == EEXIST)
765 if(fd != -1)
767 unsigned char *sfnt_data;
769 HLock(sfnt);
770 sfnt_data = *(unsigned char**)sfnt;
771 write(fd, sfnt_data, GetHandleSize(sfnt));
772 HUnlock(sfnt);
773 close(fd);
775 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
777 ret.max_size *= 2;
778 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
780 ret.array[ret.size++] = output;
782 else
784 WARN("unable to create %s\n", output);
785 HeapFree(GetProcessHeap(), 0, output);
788 ReleaseResource(sfnt);
790 HUnlock(fond);
791 ReleaseResource(fond);
792 idx++;
794 CloseResFile(res_ref);
796 return ret.array;
799 #endif /* HAVE_CARBON_CARBON_H */
801 static inline BOOL is_win9x(void)
803 return GetVersion() & 0x80000000;
806 This function builds an FT_Fixed from a float. It puts the integer part
807 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
808 It fails if the integer part of the float number is greater than SHORT_MAX.
810 static inline FT_Fixed FT_FixedFromFloat(float f)
812 short value = f;
813 unsigned short fract = (f - value) * 0xFFFF;
814 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
818 This function builds an FT_Fixed from a FIXED. It simply put f.value
819 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
821 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
823 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
827 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
829 Family *family;
830 Face *face;
831 const char *file;
832 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
833 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
835 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
836 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
838 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
840 if(face_name && strcmpiW(face_name, family->FamilyName))
841 continue;
842 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
844 if (!face->file)
845 continue;
846 file = strrchr(face->file, '/');
847 if(!file)
848 file = face->file;
849 else
850 file++;
851 if(!strcasecmp(file, file_nameA))
853 HeapFree(GetProcessHeap(), 0, file_nameA);
854 return face;
858 HeapFree(GetProcessHeap(), 0, file_nameA);
859 return NULL;
862 static Family *find_family_from_name(const WCHAR *name)
864 Family *family;
866 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
868 if(!strcmpiW(family->FamilyName, name))
869 return family;
872 return NULL;
875 static void DumpSubstList(void)
877 FontSubst *psub;
879 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
881 if(psub->from.charset != -1 || psub->to.charset != -1)
882 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
883 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
884 else
885 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
886 debugstr_w(psub->to.name));
888 return;
891 static LPWSTR strdupW(LPCWSTR p)
893 LPWSTR ret;
894 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
895 ret = HeapAlloc(GetProcessHeap(), 0, len);
896 memcpy(ret, p, len);
897 return ret;
900 static LPSTR strdupA(LPCSTR p)
902 LPSTR ret;
903 DWORD len = (strlen(p) + 1);
904 ret = HeapAlloc(GetProcessHeap(), 0, len);
905 memcpy(ret, p, len);
906 return ret;
909 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
910 INT from_charset)
912 FontSubst *element;
914 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
916 if(!strcmpiW(element->from.name, from_name) &&
917 (element->from.charset == from_charset ||
918 element->from.charset == -1))
919 return element;
922 return NULL;
925 #define ADD_FONT_SUBST_FORCE 1
927 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
929 FontSubst *from_exist, *to_exist;
931 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
933 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
935 list_remove(&from_exist->entry);
936 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
937 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
938 HeapFree(GetProcessHeap(), 0, from_exist);
939 from_exist = NULL;
942 if(!from_exist)
944 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
946 if(to_exist)
948 HeapFree(GetProcessHeap(), 0, subst->to.name);
949 subst->to.name = strdupW(to_exist->to.name);
952 list_add_tail(subst_list, &subst->entry);
954 return TRUE;
957 HeapFree(GetProcessHeap(), 0, subst->from.name);
958 HeapFree(GetProcessHeap(), 0, subst->to.name);
959 HeapFree(GetProcessHeap(), 0, subst);
960 return FALSE;
963 static void split_subst_info(NameCs *nc, LPSTR str)
965 CHAR *p = strrchr(str, ',');
966 DWORD len;
968 nc->charset = -1;
969 if(p && *(p+1)) {
970 nc->charset = strtol(p+1, NULL, 10);
971 *p = '\0';
973 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
974 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
975 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
978 static void LoadSubstList(void)
980 FontSubst *psub;
981 HKEY hkey;
982 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
983 LPSTR value;
984 LPVOID data;
986 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
987 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
988 &hkey) == ERROR_SUCCESS) {
990 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
991 &valuelen, &datalen, NULL, NULL);
993 valuelen++; /* returned value doesn't include room for '\0' */
994 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
995 data = HeapAlloc(GetProcessHeap(), 0, datalen);
997 dlen = datalen;
998 vlen = valuelen;
999 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1000 &dlen) == ERROR_SUCCESS) {
1001 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1003 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1004 split_subst_info(&psub->from, value);
1005 split_subst_info(&psub->to, data);
1007 /* Win 2000 doesn't allow mapping between different charsets
1008 or mapping of DEFAULT_CHARSET */
1009 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1010 psub->to.charset == DEFAULT_CHARSET) {
1011 HeapFree(GetProcessHeap(), 0, psub->to.name);
1012 HeapFree(GetProcessHeap(), 0, psub->from.name);
1013 HeapFree(GetProcessHeap(), 0, psub);
1014 } else {
1015 add_font_subst(&font_subst_list, psub, 0);
1017 /* reset dlen and vlen */
1018 dlen = datalen;
1019 vlen = valuelen;
1021 HeapFree(GetProcessHeap(), 0, data);
1022 HeapFree(GetProcessHeap(), 0, value);
1023 RegCloseKey(hkey);
1027 static WCHAR *get_familyname(FT_Face ft_face)
1029 WCHAR *family = NULL;
1030 FT_SfntName name;
1031 FT_UInt num_names, name_index, i;
1033 if(FT_IS_SFNT(ft_face))
1035 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1037 for(name_index = 0; name_index < num_names; name_index++)
1039 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1041 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1042 (name.language_id == GetUserDefaultLCID()) &&
1043 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1044 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1046 /* String is not nul terminated and string_len is a byte length. */
1047 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1048 for(i = 0; i < name.string_len / 2; i++)
1050 WORD *tmp = (WORD *)&name.string[i * 2];
1051 family[i] = GET_BE_WORD(*tmp);
1053 family[i] = 0;
1055 TRACE("Got localised name %s\n", debugstr_w(family));
1056 return family;
1062 return NULL;
1066 /*****************************************************************
1067 * load_sfnt_table
1069 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1070 * of FreeType that don't export this function.
1073 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1076 FT_Error err;
1078 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1079 if(pFT_Load_Sfnt_Table)
1081 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1083 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1084 else /* Do it the hard way */
1086 TT_Face tt_face = (TT_Face) ft_face;
1087 SFNT_Interface *sfnt;
1088 if (FT_Version.major==2 && FT_Version.minor==0)
1090 /* 2.0.x */
1091 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1093 else
1095 /* A field was added in the middle of the structure in 2.1.x */
1096 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1098 err = sfnt->load_any(tt_face, table, offset, buf, len);
1100 #else
1101 else
1103 static int msg;
1104 if(!msg)
1106 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1107 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1108 "Please upgrade your freetype library.\n");
1109 msg++;
1111 err = FT_Err_Unimplemented_Feature;
1113 #endif
1114 return err;
1117 static inline int TestStyles(DWORD flags, DWORD styles)
1119 return (flags & styles) == styles;
1122 static int StyleOrdering(Face *face)
1124 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1125 return 3;
1126 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1127 return 2;
1128 if (TestStyles(face->ntmFlags, NTM_BOLD))
1129 return 1;
1130 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1131 return 0;
1133 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1134 debugstr_w(face->family->FamilyName),
1135 debugstr_w(face->StyleName),
1136 face->ntmFlags);
1138 return 9999;
1141 /* Add a style of face to a font family using an ordering of the list such
1142 that regular fonts come before bold and italic, and single styles come
1143 before compound styles. */
1144 static void AddFaceToFamily(Face *face, Family *family)
1146 struct list *entry;
1148 LIST_FOR_EACH( entry, &family->faces )
1150 Face *ent = LIST_ENTRY(entry, Face, entry);
1151 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1153 list_add_before( entry, &face->entry );
1156 #define ADDFONT_EXTERNAL_FONT 0x01
1157 #define ADDFONT_FORCE_BITMAP 0x02
1158 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1160 FT_Face ft_face;
1161 TT_OS2 *pOS2;
1162 TT_Header *pHeader = NULL;
1163 WCHAR *english_family, *localised_family, *StyleW;
1164 DWORD len;
1165 Family *family;
1166 Face *face;
1167 struct list *family_elem_ptr, *face_elem_ptr;
1168 FT_Error err;
1169 FT_Long face_index = 0, num_faces;
1170 #ifdef HAVE_FREETYPE_FTWINFNT_H
1171 FT_WinFNT_HeaderRec winfnt_header;
1172 #endif
1173 int i, bitmap_num, internal_leading;
1174 FONTSIGNATURE fs;
1176 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1177 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1179 #ifdef HAVE_CARBON_CARBON_H
1180 if(file && !fake_family)
1182 char **mac_list = expand_mac_font(file);
1183 if(mac_list)
1185 BOOL had_one = FALSE;
1186 char **cursor;
1187 for(cursor = mac_list; *cursor; cursor++)
1189 had_one = TRUE;
1190 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1191 HeapFree(GetProcessHeap(), 0, *cursor);
1193 HeapFree(GetProcessHeap(), 0, mac_list);
1194 if(had_one)
1195 return 1;
1198 #endif /* HAVE_CARBON_CARBON_H */
1200 do {
1201 char *family_name = fake_family;
1203 if (file)
1205 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1206 err = pFT_New_Face(library, file, face_index, &ft_face);
1207 } else
1209 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1210 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1213 if(err != 0) {
1214 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1215 return 0;
1218 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1219 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1220 pFT_Done_Face(ft_face);
1221 return 0;
1224 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1225 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1226 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1227 pFT_Done_Face(ft_face);
1228 return 0;
1231 if(FT_IS_SFNT(ft_face))
1233 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1234 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1235 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1237 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1238 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1239 pFT_Done_Face(ft_face);
1240 return 0;
1243 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1244 we don't want to load these. */
1245 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1247 FT_ULong len = 0;
1249 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1251 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1252 pFT_Done_Face(ft_face);
1253 return 0;
1258 if(!ft_face->family_name || !ft_face->style_name) {
1259 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1260 pFT_Done_Face(ft_face);
1261 return 0;
1264 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1266 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1267 pFT_Done_Face(ft_face);
1268 return 0;
1271 if (target_family)
1273 localised_family = get_familyname(ft_face);
1274 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1276 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1277 HeapFree(GetProcessHeap(), 0, localised_family);
1278 num_faces = ft_face->num_faces;
1279 pFT_Done_Face(ft_face);
1280 continue;
1282 HeapFree(GetProcessHeap(), 0, localised_family);
1285 if(!family_name)
1286 family_name = ft_face->family_name;
1288 bitmap_num = 0;
1289 do {
1290 My_FT_Bitmap_Size *size = NULL;
1291 FT_ULong tmp_size;
1293 if(!FT_IS_SCALABLE(ft_face))
1294 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1296 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1297 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1298 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1300 localised_family = NULL;
1301 if(!fake_family) {
1302 localised_family = get_familyname(ft_face);
1303 if(localised_family && !strcmpW(localised_family, english_family)) {
1304 HeapFree(GetProcessHeap(), 0, localised_family);
1305 localised_family = NULL;
1309 family = NULL;
1310 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1311 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1312 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1313 break;
1314 family = NULL;
1316 if(!family) {
1317 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1318 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1319 list_init(&family->faces);
1320 list_add_tail(&font_list, &family->entry);
1322 if(localised_family) {
1323 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1324 subst->from.name = strdupW(english_family);
1325 subst->from.charset = -1;
1326 subst->to.name = strdupW(localised_family);
1327 subst->to.charset = -1;
1328 add_font_subst(&font_subst_list, subst, 0);
1331 HeapFree(GetProcessHeap(), 0, localised_family);
1332 HeapFree(GetProcessHeap(), 0, english_family);
1334 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1335 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1336 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1338 internal_leading = 0;
1339 memset(&fs, 0, sizeof(fs));
1341 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1342 if(pOS2) {
1343 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1344 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1345 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1346 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1347 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1348 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1349 if(pOS2->version == 0) {
1350 FT_UInt dummy;
1352 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1353 fs.fsCsb[0] |= FS_LATIN1;
1354 else
1355 fs.fsCsb[0] |= FS_SYMBOL;
1358 #ifdef HAVE_FREETYPE_FTWINFNT_H
1359 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1360 CHARSETINFO csi;
1361 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1362 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1363 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1364 fs = csi.fs;
1365 internal_leading = winfnt_header.internal_leading;
1367 #endif
1369 face_elem_ptr = list_head(&family->faces);
1370 while(face_elem_ptr) {
1371 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1372 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1373 if(!strcmpW(face->StyleName, StyleW) &&
1374 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1375 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1376 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1377 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1379 if(fake_family) {
1380 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1381 HeapFree(GetProcessHeap(), 0, StyleW);
1382 pFT_Done_Face(ft_face);
1383 return 1;
1385 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1386 TRACE("Original font is newer so skipping this one\n");
1387 HeapFree(GetProcessHeap(), 0, StyleW);
1388 pFT_Done_Face(ft_face);
1389 return 1;
1390 } else {
1391 TRACE("Replacing original with this one\n");
1392 list_remove(&face->entry);
1393 HeapFree(GetProcessHeap(), 0, face->file);
1394 HeapFree(GetProcessHeap(), 0, face->StyleName);
1395 HeapFree(GetProcessHeap(), 0, face);
1396 break;
1400 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1401 face->cached_enum_data = NULL;
1402 face->StyleName = StyleW;
1403 if (file)
1405 face->file = strdupA(file);
1406 face->font_data_ptr = NULL;
1407 face->font_data_size = 0;
1409 else
1411 face->file = NULL;
1412 face->font_data_ptr = font_data_ptr;
1413 face->font_data_size = font_data_size;
1415 face->face_index = face_index;
1416 face->ntmFlags = 0;
1417 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1418 face->ntmFlags |= NTM_ITALIC;
1419 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1420 face->ntmFlags |= NTM_BOLD;
1421 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1422 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1423 face->family = family;
1424 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1425 face->fs = fs;
1426 memset(&face->fs_links, 0, sizeof(face->fs_links));
1428 if(FT_IS_SCALABLE(ft_face)) {
1429 memset(&face->size, 0, sizeof(face->size));
1430 face->scalable = TRUE;
1431 } else {
1432 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1433 size->height, size->width, size->size >> 6,
1434 size->x_ppem >> 6, size->y_ppem >> 6);
1435 face->size.height = size->height;
1436 face->size.width = size->width;
1437 face->size.size = size->size;
1438 face->size.x_ppem = size->x_ppem;
1439 face->size.y_ppem = size->y_ppem;
1440 face->size.internal_leading = internal_leading;
1441 face->scalable = FALSE;
1444 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1445 tmp_size = 0;
1446 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1448 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1449 face->ntmFlags |= NTM_PS_OPENTYPE;
1452 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1453 face->fs.fsCsb[0], face->fs.fsCsb[1],
1454 face->fs.fsUsb[0], face->fs.fsUsb[1],
1455 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1458 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1459 for(i = 0; i < ft_face->num_charmaps; i++) {
1460 switch(ft_face->charmaps[i]->encoding) {
1461 case FT_ENCODING_UNICODE:
1462 case FT_ENCODING_APPLE_ROMAN:
1463 face->fs.fsCsb[0] |= FS_LATIN1;
1464 break;
1465 case FT_ENCODING_MS_SYMBOL:
1466 face->fs.fsCsb[0] |= FS_SYMBOL;
1467 break;
1468 default:
1469 break;
1474 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1475 have_installed_roman_font = TRUE;
1477 AddFaceToFamily(face, family);
1479 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1481 num_faces = ft_face->num_faces;
1482 pFT_Done_Face(ft_face);
1483 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1484 debugstr_w(StyleW));
1485 } while(num_faces > ++face_index);
1486 return num_faces;
1489 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1491 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1494 static void DumpFontList(void)
1496 Family *family;
1497 Face *face;
1498 struct list *family_elem_ptr, *face_elem_ptr;
1500 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1501 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1502 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1503 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1504 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1505 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1506 if(!face->scalable)
1507 TRACE(" %d", face->size.height);
1508 TRACE("\n");
1511 return;
1514 /***********************************************************
1515 * The replacement list is a way to map an entire font
1516 * family onto another family. For example adding
1518 * [HKCU\Software\Wine\Fonts\Replacements]
1519 * "Wingdings"="Winedings"
1521 * would enumerate the Winedings font both as Winedings and
1522 * Wingdings. However if a real Wingdings font is present the
1523 * replacement does not take place.
1526 static void LoadReplaceList(void)
1528 HKEY hkey;
1529 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1530 LPWSTR value;
1531 LPVOID data;
1532 Family *family;
1533 Face *face;
1534 struct list *family_elem_ptr, *face_elem_ptr;
1535 CHAR familyA[400];
1537 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1538 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1540 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1541 &valuelen, &datalen, NULL, NULL);
1543 valuelen++; /* returned value doesn't include room for '\0' */
1544 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1545 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1547 dlen = datalen;
1548 vlen = valuelen;
1549 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1550 &dlen) == ERROR_SUCCESS) {
1551 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1552 /* "NewName"="Oldname" */
1553 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1555 /* Find the old family and hence all of the font files
1556 in that family */
1557 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1558 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1559 if(!strcmpiW(family->FamilyName, data)) {
1560 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1561 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1562 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1563 debugstr_w(face->StyleName), familyA);
1564 /* Now add a new entry with the new family name */
1565 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1567 break;
1570 /* reset dlen and vlen */
1571 dlen = datalen;
1572 vlen = valuelen;
1574 HeapFree(GetProcessHeap(), 0, data);
1575 HeapFree(GetProcessHeap(), 0, value);
1576 RegCloseKey(hkey);
1580 /*************************************************************
1581 * init_system_links
1583 static BOOL init_system_links(void)
1585 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1586 'W','i','n','d','o','w','s',' ','N','T','\\',
1587 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1588 'S','y','s','t','e','m','L','i','n','k',0};
1589 HKEY hkey;
1590 BOOL ret = FALSE;
1591 DWORD type, max_val, max_data, val_len, data_len, index;
1592 WCHAR *value, *data;
1593 WCHAR *entry, *next;
1594 SYSTEM_LINKS *font_link, *system_font_link;
1595 CHILD_FONT *child_font;
1596 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1597 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1598 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1599 FONTSIGNATURE fs;
1600 Family *family;
1601 Face *face;
1602 FontSubst *psub;
1604 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1606 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1607 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1608 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1609 val_len = max_val + 1;
1610 data_len = max_data;
1611 index = 0;
1612 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1614 TRACE("%s:\n", debugstr_w(value));
1616 memset(&fs, 0, sizeof(fs));
1617 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1618 psub = get_font_subst(&font_subst_list, value, -1);
1619 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1620 list_init(&font_link->links);
1621 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1623 WCHAR *face_name;
1624 CHILD_FONT *child_font;
1626 TRACE("\t%s\n", debugstr_w(entry));
1628 next = entry + strlenW(entry) + 1;
1630 face_name = strchrW(entry, ',');
1631 if(face_name)
1633 *face_name++ = 0;
1634 while(isspaceW(*face_name))
1635 face_name++;
1637 psub = get_font_subst(&font_subst_list, face_name, -1);
1638 if(psub)
1639 face_name = psub->to.name;
1641 face = find_face_from_filename(entry, face_name);
1642 if(!face)
1644 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1645 continue;
1648 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1649 child_font->face = face;
1650 child_font->font = NULL;
1651 fs.fsCsb[0] |= face->fs.fsCsb[0];
1652 fs.fsCsb[1] |= face->fs.fsCsb[1];
1653 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1654 list_add_tail(&font_link->links, &child_font->entry);
1656 family = find_family_from_name(font_link->font_name);
1657 if(family)
1659 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1661 face->fs_links = fs;
1664 list_add_tail(&system_links, &font_link->entry);
1665 val_len = max_val + 1;
1666 data_len = max_data;
1669 HeapFree(GetProcessHeap(), 0, value);
1670 HeapFree(GetProcessHeap(), 0, data);
1671 RegCloseKey(hkey);
1674 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1675 that Tahoma has */
1677 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1678 system_font_link->font_name = strdupW(System);
1679 list_init(&system_font_link->links);
1681 face = find_face_from_filename(tahoma_ttf, Tahoma);
1682 if(face)
1684 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1685 child_font->face = face;
1686 child_font->font = NULL;
1687 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1688 list_add_tail(&system_font_link->links, &child_font->entry);
1690 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1692 if(!strcmpiW(font_link->font_name, Tahoma))
1694 CHILD_FONT *font_link_entry;
1695 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1697 CHILD_FONT *new_child;
1698 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1699 new_child->face = font_link_entry->face;
1700 new_child->font = NULL;
1701 list_add_tail(&system_font_link->links, &new_child->entry);
1703 break;
1706 list_add_tail(&system_links, &system_font_link->entry);
1707 return ret;
1710 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1712 DIR *dir;
1713 struct dirent *dent;
1714 char path[MAX_PATH];
1716 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1718 dir = opendir(dirname);
1719 if(!dir) {
1720 WARN("Can't open directory %s\n", debugstr_a(dirname));
1721 return FALSE;
1723 while((dent = readdir(dir)) != NULL) {
1724 struct stat statbuf;
1726 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1727 continue;
1729 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1731 sprintf(path, "%s/%s", dirname, dent->d_name);
1733 if(stat(path, &statbuf) == -1)
1735 WARN("Can't stat %s\n", debugstr_a(path));
1736 continue;
1738 if(S_ISDIR(statbuf.st_mode))
1739 ReadFontDir(path, external_fonts);
1740 else
1741 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1743 closedir(dir);
1744 return TRUE;
1747 static void load_fontconfig_fonts(void)
1749 #ifdef SONAME_LIBFONTCONFIG
1750 void *fc_handle = NULL;
1751 FcConfig *config;
1752 FcPattern *pat;
1753 FcObjectSet *os;
1754 FcFontSet *fontset;
1755 int i, len;
1756 char *file;
1757 const char *ext;
1759 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1760 if(!fc_handle) {
1761 TRACE("Wine cannot find the fontconfig library (%s).\n",
1762 SONAME_LIBFONTCONFIG);
1763 return;
1765 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1766 LOAD_FUNCPTR(FcConfigGetCurrent);
1767 LOAD_FUNCPTR(FcFontList);
1768 LOAD_FUNCPTR(FcFontSetDestroy);
1769 LOAD_FUNCPTR(FcInit);
1770 LOAD_FUNCPTR(FcObjectSetAdd);
1771 LOAD_FUNCPTR(FcObjectSetCreate);
1772 LOAD_FUNCPTR(FcObjectSetDestroy);
1773 LOAD_FUNCPTR(FcPatternCreate);
1774 LOAD_FUNCPTR(FcPatternDestroy);
1775 LOAD_FUNCPTR(FcPatternGetBool);
1776 LOAD_FUNCPTR(FcPatternGetString);
1777 #undef LOAD_FUNCPTR
1779 if(!pFcInit()) return;
1781 config = pFcConfigGetCurrent();
1782 pat = pFcPatternCreate();
1783 os = pFcObjectSetCreate();
1784 pFcObjectSetAdd(os, FC_FILE);
1785 pFcObjectSetAdd(os, FC_SCALABLE);
1786 fontset = pFcFontList(config, pat, os);
1787 if(!fontset) return;
1788 for(i = 0; i < fontset->nfont; i++) {
1789 FcBool scalable;
1791 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1792 continue;
1793 TRACE("fontconfig: %s\n", file);
1795 /* We're just interested in OT/TT fonts for now, so this hack just
1796 picks up the scalable fonts without extensions .pf[ab] to save time
1797 loading every other font */
1799 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1801 TRACE("not scalable\n");
1802 continue;
1805 len = strlen( file );
1806 if(len < 4) continue;
1807 ext = &file[ len - 3 ];
1808 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1809 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1811 pFcFontSetDestroy(fontset);
1812 pFcObjectSetDestroy(os);
1813 pFcPatternDestroy(pat);
1814 sym_not_found:
1815 #endif
1816 return;
1819 static BOOL load_font_from_data_dir(LPCWSTR file)
1821 BOOL ret = FALSE;
1822 const char *data_dir = wine_get_data_dir();
1824 if (!data_dir) data_dir = wine_get_build_dir();
1826 if (data_dir)
1828 INT len;
1829 char *unix_name;
1831 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1833 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1835 strcpy(unix_name, data_dir);
1836 strcat(unix_name, "/fonts/");
1838 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1840 EnterCriticalSection( &freetype_cs );
1841 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1842 LeaveCriticalSection( &freetype_cs );
1843 HeapFree(GetProcessHeap(), 0, unix_name);
1845 return ret;
1848 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1850 static const WCHAR slashW[] = {'\\','\0'};
1851 BOOL ret = FALSE;
1852 WCHAR windowsdir[MAX_PATH];
1853 char *unixname;
1855 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1856 strcatW(windowsdir, fontsW);
1857 strcatW(windowsdir, slashW);
1858 strcatW(windowsdir, file);
1859 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1860 EnterCriticalSection( &freetype_cs );
1861 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1862 LeaveCriticalSection( &freetype_cs );
1863 HeapFree(GetProcessHeap(), 0, unixname);
1865 return ret;
1868 static void load_system_fonts(void)
1870 HKEY hkey;
1871 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1872 const WCHAR * const *value;
1873 DWORD dlen, type;
1874 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1875 char *unixname;
1877 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1878 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1879 strcatW(windowsdir, fontsW);
1880 for(value = SystemFontValues; *value; value++) {
1881 dlen = sizeof(data);
1882 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1883 type == REG_SZ) {
1884 BOOL added = FALSE;
1886 sprintfW(pathW, fmtW, windowsdir, data);
1887 if((unixname = wine_get_unix_file_name(pathW))) {
1888 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1889 HeapFree(GetProcessHeap(), 0, unixname);
1891 if (!added)
1892 load_font_from_data_dir(data);
1895 RegCloseKey(hkey);
1899 /*************************************************************
1901 * This adds registry entries for any externally loaded fonts
1902 * (fonts from fontconfig or FontDirs). It also deletes entries
1903 * of no longer existing fonts.
1906 static void update_reg_entries(void)
1908 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1909 LPWSTR valueW;
1910 DWORD len, len_fam;
1911 Family *family;
1912 Face *face;
1913 struct list *family_elem_ptr, *face_elem_ptr;
1914 WCHAR *file;
1915 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1916 static const WCHAR spaceW[] = {' ', '\0'};
1917 char *path;
1919 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1920 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1921 ERR("Can't create Windows font reg key\n");
1922 goto end;
1925 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1926 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1927 ERR("Can't create Windows font reg key\n");
1928 goto end;
1931 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1932 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1933 ERR("Can't create external font reg key\n");
1934 goto end;
1937 /* enumerate the fonts and add external ones to the two keys */
1939 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1940 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1941 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1942 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1943 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1944 if(!face->external) continue;
1945 len = len_fam;
1946 if (!(face->ntmFlags & NTM_REGULAR))
1947 len = len_fam + strlenW(face->StyleName) + 1;
1948 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1949 strcpyW(valueW, family->FamilyName);
1950 if(len != len_fam) {
1951 strcatW(valueW, spaceW);
1952 strcatW(valueW, face->StyleName);
1954 strcatW(valueW, TrueType);
1956 file = wine_get_dos_file_name(face->file);
1957 if(file)
1958 len = strlenW(file) + 1;
1959 else
1961 if((path = strrchr(face->file, '/')) == NULL)
1962 path = face->file;
1963 else
1964 path++;
1965 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1967 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1968 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1970 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1971 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1972 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1974 HeapFree(GetProcessHeap(), 0, file);
1975 HeapFree(GetProcessHeap(), 0, valueW);
1978 end:
1979 if(external_key) RegCloseKey(external_key);
1980 if(win9x_key) RegCloseKey(win9x_key);
1981 if(winnt_key) RegCloseKey(winnt_key);
1982 return;
1985 static void delete_external_font_keys(void)
1987 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1988 DWORD dlen, vlen, datalen, valuelen, i, type;
1989 LPWSTR valueW;
1990 LPVOID data;
1992 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1993 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1994 ERR("Can't create Windows font reg key\n");
1995 goto end;
1998 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1999 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2000 ERR("Can't create Windows font reg key\n");
2001 goto end;
2004 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2005 ERR("Can't create external font reg key\n");
2006 goto end;
2009 /* Delete all external fonts added last time */
2011 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2012 &valuelen, &datalen, NULL, NULL);
2013 valuelen++; /* returned value doesn't include room for '\0' */
2014 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2015 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2017 dlen = datalen * sizeof(WCHAR);
2018 vlen = valuelen;
2019 i = 0;
2020 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2021 &dlen) == ERROR_SUCCESS) {
2023 RegDeleteValueW(winnt_key, valueW);
2024 RegDeleteValueW(win9x_key, valueW);
2025 /* reset dlen and vlen */
2026 dlen = datalen;
2027 vlen = valuelen;
2029 HeapFree(GetProcessHeap(), 0, data);
2030 HeapFree(GetProcessHeap(), 0, valueW);
2032 /* Delete the old external fonts key */
2033 RegCloseKey(external_key);
2034 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2036 end:
2037 if(win9x_key) RegCloseKey(win9x_key);
2038 if(winnt_key) RegCloseKey(winnt_key);
2041 /*************************************************************
2042 * WineEngAddFontResourceEx
2045 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2047 INT ret = 0;
2048 if (ft_handle) /* do it only if we have freetype up and running */
2050 char *unixname;
2052 if(flags)
2053 FIXME("Ignoring flags %x\n", flags);
2055 if((unixname = wine_get_unix_file_name(file)))
2057 EnterCriticalSection( &freetype_cs );
2058 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2059 LeaveCriticalSection( &freetype_cs );
2060 HeapFree(GetProcessHeap(), 0, unixname);
2062 if (!ret && !strchrW(file, '\\')) {
2063 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2064 ret = load_font_from_winfonts_dir(file);
2065 if (!ret) {
2066 /* Try in datadir/fonts (or builddir/fonts),
2067 * needed for Magic the Gathering Online
2069 ret = load_font_from_data_dir(file);
2073 return ret;
2076 /*************************************************************
2077 * WineEngAddFontMemResourceEx
2080 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2082 if (ft_handle) /* do it only if we have freetype up and running */
2084 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2086 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2087 memcpy(pFontCopy, pbFont, cbFont);
2089 EnterCriticalSection( &freetype_cs );
2090 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2091 LeaveCriticalSection( &freetype_cs );
2093 if (*pcFonts == 0)
2095 TRACE("AddFontToList failed\n");
2096 HeapFree(GetProcessHeap(), 0, pFontCopy);
2097 return NULL;
2099 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2100 * For now return something unique but quite random
2102 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2103 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2106 *pcFonts = 0;
2107 return 0;
2110 /*************************************************************
2111 * WineEngRemoveFontResourceEx
2114 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2116 FIXME(":stub\n");
2117 return TRUE;
2120 static const struct nls_update_font_list
2122 UINT ansi_cp, oem_cp;
2123 const char *oem, *fixed, *system;
2124 const char *courier, *serif, *small, *sserif;
2125 /* these are for font substitutes */
2126 const char *shelldlg, *tmsrmn;
2127 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2128 *helv_0, *tmsrmn_0;
2129 const struct subst
2131 const char *from, *to;
2132 } arial_0, courier_new_0, times_new_roman_0;
2133 } nls_update_font_list[] =
2135 /* Latin 1 (United States) */
2136 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2137 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2138 "Tahoma","Times New Roman",
2139 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2140 { 0 }, { 0 }, { 0 }
2142 /* Latin 1 (Multilingual) */
2143 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2144 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2145 "Tahoma","Times New Roman", /* FIXME unverified */
2146 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2147 { 0 }, { 0 }, { 0 }
2149 /* Eastern Europe */
2150 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2151 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2152 "Tahoma","Times New Roman", /* FIXME unverified */
2153 "Fixedsys,238", "System,238",
2154 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2155 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2156 { "Arial CE,0", "Arial,238" },
2157 { "Courier New CE,0", "Courier New,238" },
2158 { "Times New Roman CE,0", "Times New Roman,238" }
2160 /* Cyrillic */
2161 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2162 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2163 "Tahoma","Times New Roman", /* FIXME unverified */
2164 "Fixedsys,204", "System,204",
2165 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2166 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2167 { "Arial Cyr,0", "Arial,204" },
2168 { "Courier New Cyr,0", "Courier New,204" },
2169 { "Times New Roman Cyr,0", "Times New Roman,204" }
2171 /* Greek */
2172 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2173 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2174 "Tahoma","Times New Roman", /* FIXME unverified */
2175 "Fixedsys,161", "System,161",
2176 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2177 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2178 { "Arial Greek,0", "Arial,161" },
2179 { "Courier New Greek,0", "Courier New,161" },
2180 { "Times New Roman Greek,0", "Times New Roman,161" }
2182 /* Turkish */
2183 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2184 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2185 "Tahoma","Times New Roman", /* FIXME unverified */
2186 "Fixedsys,162", "System,162",
2187 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2188 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2189 { "Arial Tur,0", "Arial,162" },
2190 { "Courier New Tur,0", "Courier New,162" },
2191 { "Times New Roman Tur,0", "Times New Roman,162" }
2193 /* Hebrew */
2194 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2195 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2196 "Tahoma","Times New Roman", /* FIXME unverified */
2197 "Fixedsys,177", "System,177",
2198 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2199 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2200 { 0 }, { 0 }, { 0 }
2202 /* Arabic */
2203 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2204 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,178", "System,178",
2207 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2208 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2209 { 0 }, { 0 }, { 0 }
2211 /* Baltic */
2212 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2213 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2214 "Tahoma","Times New Roman", /* FIXME unverified */
2215 "Fixedsys,186", "System,186",
2216 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2217 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2218 { "Arial Baltic,0", "Arial,186" },
2219 { "Courier New Baltic,0", "Courier New,186" },
2220 { "Times New Roman Baltic,0", "Times New Roman,186" }
2222 /* Vietnamese */
2223 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2224 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2225 "Tahoma","Times New Roman", /* FIXME unverified */
2226 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2227 { 0 }, { 0 }, { 0 }
2229 /* Thai */
2230 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2231 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2232 "Tahoma","Times New Roman", /* FIXME unverified */
2233 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2234 { 0 }, { 0 }, { 0 }
2236 /* Japanese */
2237 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2238 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2239 "MS UI Gothic","MS Serif",
2240 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2241 { 0 }, { 0 }, { 0 }
2243 /* Chinese Simplified */
2244 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2245 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2246 "Tahoma", "Times New Roman", /* FIXME unverified */
2247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2248 { 0 }, { 0 }, { 0 }
2250 /* Korean */
2251 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2253 "Gulim", "Batang",
2254 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2255 { 0 }, { 0 }, { 0 }
2257 /* Chinese Traditional */
2258 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2259 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2260 "PMingLiU", "MingLiU",
2261 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2262 { 0 }, { 0 }, { 0 }
2266 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2268 return ( ansi_cp == 932 /* CP932 for Japanese */
2269 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2270 || ansi_cp == 949 /* CP949 for Korean */
2271 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2274 static inline HKEY create_fonts_NT_registry_key(void)
2276 HKEY hkey = 0;
2278 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2279 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2280 return hkey;
2283 static inline HKEY create_fonts_9x_registry_key(void)
2285 HKEY hkey = 0;
2287 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2288 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2289 return hkey;
2292 static inline HKEY create_config_fonts_registry_key(void)
2294 HKEY hkey = 0;
2296 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2297 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2298 return hkey;
2301 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2303 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2304 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2305 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2306 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2309 static void set_value_key(HKEY hkey, const char *name, const char *value)
2311 if (value)
2312 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2313 else if (name)
2314 RegDeleteValueA(hkey, name);
2317 static void update_font_info(void)
2319 char buf[40], cpbuf[40];
2320 DWORD len, type;
2321 HKEY hkey = 0;
2322 UINT i, ansi_cp = 0, oem_cp = 0;
2323 BOOL done = FALSE;
2325 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2326 return;
2328 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2329 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2330 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2331 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2332 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2334 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2335 if (is_dbcs_ansi_cp(ansi_cp))
2336 use_default_fallback = TRUE;
2338 len = sizeof(buf);
2339 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2341 if (!strcmp( buf, cpbuf )) /* already set correctly */
2343 RegCloseKey(hkey);
2344 return;
2346 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2348 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2350 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2351 RegCloseKey(hkey);
2353 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2355 HKEY hkey;
2357 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2358 nls_update_font_list[i].oem_cp == oem_cp)
2360 hkey = create_config_fonts_registry_key();
2361 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2362 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2363 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2364 RegCloseKey(hkey);
2366 hkey = create_fonts_NT_registry_key();
2367 add_font_list(hkey, &nls_update_font_list[i]);
2368 RegCloseKey(hkey);
2370 hkey = create_fonts_9x_registry_key();
2371 add_font_list(hkey, &nls_update_font_list[i]);
2372 RegCloseKey(hkey);
2374 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2376 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2377 strlen(nls_update_font_list[i].shelldlg)+1);
2378 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2379 strlen(nls_update_font_list[i].tmsrmn)+1);
2381 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2382 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2383 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2384 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2385 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2386 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2387 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2388 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2390 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2391 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2392 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2394 RegCloseKey(hkey);
2396 done = TRUE;
2398 else
2400 /* Delete the FontSubstitutes from other locales */
2401 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2403 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2404 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2405 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2406 RegCloseKey(hkey);
2410 if (!done)
2411 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2415 static BOOL init_freetype(void)
2417 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2418 if(!ft_handle) {
2419 WINE_MESSAGE(
2420 "Wine cannot find the FreeType font library. To enable Wine to\n"
2421 "use TrueType fonts please install a version of FreeType greater than\n"
2422 "or equal to 2.0.5.\n"
2423 "http://www.freetype.org\n");
2424 return FALSE;
2427 #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;}
2429 LOAD_FUNCPTR(FT_Vector_Unit)
2430 LOAD_FUNCPTR(FT_Done_Face)
2431 LOAD_FUNCPTR(FT_Get_Char_Index)
2432 LOAD_FUNCPTR(FT_Get_Module)
2433 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2434 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2435 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2436 LOAD_FUNCPTR(FT_Init_FreeType)
2437 LOAD_FUNCPTR(FT_Load_Glyph)
2438 LOAD_FUNCPTR(FT_Matrix_Multiply)
2439 LOAD_FUNCPTR(FT_MulFix)
2440 LOAD_FUNCPTR(FT_New_Face)
2441 LOAD_FUNCPTR(FT_New_Memory_Face)
2442 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2443 LOAD_FUNCPTR(FT_Outline_Transform)
2444 LOAD_FUNCPTR(FT_Outline_Translate)
2445 LOAD_FUNCPTR(FT_Select_Charmap)
2446 LOAD_FUNCPTR(FT_Set_Charmap)
2447 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2448 LOAD_FUNCPTR(FT_Vector_Transform)
2450 #undef LOAD_FUNCPTR
2451 /* Don't warn if these ones are missing */
2452 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2453 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2454 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2455 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2456 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2457 #ifdef HAVE_FREETYPE_FTWINFNT_H
2458 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2459 #endif
2460 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2461 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2462 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2463 <= 2.0.3 has FT_Sqrt64 */
2464 goto sym_not_found;
2467 if(pFT_Init_FreeType(&library) != 0) {
2468 ERR("Can't init FreeType library\n");
2469 wine_dlclose(ft_handle, NULL, 0);
2470 ft_handle = NULL;
2471 return FALSE;
2473 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2474 if (pFT_Library_Version)
2475 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2477 if (FT_Version.major<=0)
2479 FT_Version.major=2;
2480 FT_Version.minor=0;
2481 FT_Version.patch=5;
2483 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2484 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2485 ((FT_Version.minor << 8) & 0x00ff00) |
2486 ((FT_Version.patch ) & 0x0000ff);
2488 return TRUE;
2490 sym_not_found:
2491 WINE_MESSAGE(
2492 "Wine cannot find certain functions that it needs inside the FreeType\n"
2493 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2494 "FreeType to at least version 2.0.5.\n"
2495 "http://www.freetype.org\n");
2496 wine_dlclose(ft_handle, NULL, 0);
2497 ft_handle = NULL;
2498 return FALSE;
2501 /*************************************************************
2502 * WineEngInit
2504 * Initialize FreeType library and create a list of available faces
2506 BOOL WineEngInit(void)
2508 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2509 static const WCHAR pathW[] = {'P','a','t','h',0};
2510 HKEY hkey;
2511 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2512 LPVOID data;
2513 WCHAR windowsdir[MAX_PATH];
2514 char *unixname;
2515 HANDLE font_mutex;
2516 const char *data_dir;
2518 TRACE("\n");
2520 /* update locale dependent font info in registry */
2521 update_font_info();
2523 if(!init_freetype()) return FALSE;
2525 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2526 ERR("Failed to create font mutex\n");
2527 return FALSE;
2529 WaitForSingleObject(font_mutex, INFINITE);
2531 delete_external_font_keys();
2533 /* load the system bitmap fonts */
2534 load_system_fonts();
2536 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2537 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2538 strcatW(windowsdir, fontsW);
2539 if((unixname = wine_get_unix_file_name(windowsdir)))
2541 ReadFontDir(unixname, FALSE);
2542 HeapFree(GetProcessHeap(), 0, unixname);
2545 /* load the system truetype fonts */
2546 data_dir = wine_get_data_dir();
2547 if (!data_dir) data_dir = wine_get_build_dir();
2548 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2549 strcpy(unixname, data_dir);
2550 strcat(unixname, "/fonts/");
2551 ReadFontDir(unixname, TRUE);
2552 HeapFree(GetProcessHeap(), 0, unixname);
2555 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2556 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2557 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2558 will skip these. */
2559 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2560 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2561 &hkey) == ERROR_SUCCESS) {
2562 LPWSTR valueW;
2563 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2564 &valuelen, &datalen, NULL, NULL);
2566 valuelen++; /* returned value doesn't include room for '\0' */
2567 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2568 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2569 if (valueW && data)
2571 dlen = datalen * sizeof(WCHAR);
2572 vlen = valuelen;
2573 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2574 &dlen) == ERROR_SUCCESS) {
2575 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2577 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2579 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2580 HeapFree(GetProcessHeap(), 0, unixname);
2583 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2585 WCHAR pathW[MAX_PATH];
2586 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2587 BOOL added = FALSE;
2589 sprintfW(pathW, fmtW, windowsdir, data);
2590 if((unixname = wine_get_unix_file_name(pathW)))
2592 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2593 HeapFree(GetProcessHeap(), 0, unixname);
2595 if (!added)
2596 load_font_from_data_dir(data);
2598 /* reset dlen and vlen */
2599 dlen = datalen;
2600 vlen = valuelen;
2603 HeapFree(GetProcessHeap(), 0, data);
2604 HeapFree(GetProcessHeap(), 0, valueW);
2605 RegCloseKey(hkey);
2608 load_fontconfig_fonts();
2610 /* then look in any directories that we've specified in the config file */
2611 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2612 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2614 DWORD len;
2615 LPWSTR valueW;
2616 LPSTR valueA, ptr;
2618 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2620 len += sizeof(WCHAR);
2621 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2622 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2624 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2625 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2626 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2627 TRACE( "got font path %s\n", debugstr_a(valueA) );
2628 ptr = valueA;
2629 while (ptr)
2631 LPSTR next = strchr( ptr, ':' );
2632 if (next) *next++ = 0;
2633 ReadFontDir( ptr, TRUE );
2634 ptr = next;
2636 HeapFree( GetProcessHeap(), 0, valueA );
2638 HeapFree( GetProcessHeap(), 0, valueW );
2640 RegCloseKey(hkey);
2643 DumpFontList();
2644 LoadSubstList();
2645 DumpSubstList();
2646 LoadReplaceList();
2647 update_reg_entries();
2649 init_system_links();
2651 ReleaseMutex(font_mutex);
2652 return TRUE;
2656 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2658 TT_OS2 *pOS2;
2659 TT_HoriHeader *pHori;
2661 LONG ppem;
2663 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2664 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2666 if(height == 0) height = 16;
2668 /* Calc. height of EM square:
2670 * For +ve lfHeight we have
2671 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2672 * Re-arranging gives:
2673 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2675 * For -ve lfHeight we have
2676 * |lfHeight| = ppem
2677 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2678 * with il = winAscent + winDescent - units_per_em]
2682 if(height > 0) {
2683 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2684 ppem = ft_face->units_per_EM * height /
2685 (pHori->Ascender - pHori->Descender);
2686 else
2687 ppem = ft_face->units_per_EM * height /
2688 (pOS2->usWinAscent + pOS2->usWinDescent);
2690 else
2691 ppem = -height;
2693 return ppem;
2696 static struct font_mapping *map_font_file( const char *name )
2698 struct font_mapping *mapping;
2699 struct stat st;
2700 int fd;
2702 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2703 if (fstat( fd, &st ) == -1) goto error;
2705 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2707 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2709 mapping->refcount++;
2710 close( fd );
2711 return mapping;
2714 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2715 goto error;
2717 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2718 close( fd );
2720 if (mapping->data == MAP_FAILED)
2722 HeapFree( GetProcessHeap(), 0, mapping );
2723 return NULL;
2725 mapping->refcount = 1;
2726 mapping->dev = st.st_dev;
2727 mapping->ino = st.st_ino;
2728 mapping->size = st.st_size;
2729 list_add_tail( &mappings_list, &mapping->entry );
2730 return mapping;
2732 error:
2733 close( fd );
2734 return NULL;
2737 static void unmap_font_file( struct font_mapping *mapping )
2739 if (!--mapping->refcount)
2741 list_remove( &mapping->entry );
2742 munmap( mapping->data, mapping->size );
2743 HeapFree( GetProcessHeap(), 0, mapping );
2747 static LONG load_VDMX(GdiFont*, LONG);
2749 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2751 FT_Error err;
2752 FT_Face ft_face;
2753 void *data_ptr;
2754 DWORD data_size;
2756 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2758 if (face->file)
2760 if (!(font->mapping = map_font_file( face->file )))
2762 WARN("failed to map %s\n", debugstr_a(face->file));
2763 return 0;
2765 data_ptr = font->mapping->data;
2766 data_size = font->mapping->size;
2768 else
2770 data_ptr = face->font_data_ptr;
2771 data_size = face->font_data_size;
2774 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2775 if(err) {
2776 ERR("FT_New_Face rets %d\n", err);
2777 return 0;
2780 /* set it here, as load_VDMX needs it */
2781 font->ft_face = ft_face;
2783 if(FT_IS_SCALABLE(ft_face)) {
2784 /* load the VDMX table if we have one */
2785 font->ppem = load_VDMX(font, height);
2786 if(font->ppem == 0)
2787 font->ppem = calc_ppem_for_height(ft_face, height);
2789 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2790 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2791 } else {
2792 font->ppem = height;
2793 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2794 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2796 return ft_face;
2800 static int get_nearest_charset(Face *face, int *cp)
2802 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2803 a single face with the requested charset. The idea is to check if
2804 the selected font supports the current ANSI codepage, if it does
2805 return the corresponding charset, else return the first charset */
2807 CHARSETINFO csi;
2808 int acp = GetACP(), i;
2809 DWORD fs0;
2811 *cp = acp;
2812 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2813 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2814 return csi.ciCharset;
2816 for(i = 0; i < 32; i++) {
2817 fs0 = 1L << i;
2818 if(face->fs.fsCsb[0] & fs0) {
2819 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2820 *cp = csi.ciACP;
2821 return csi.ciCharset;
2823 else
2824 FIXME("TCI failing on %x\n", fs0);
2828 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2829 face->fs.fsCsb[0], face->file);
2830 *cp = acp;
2831 return DEFAULT_CHARSET;
2834 static GdiFont *alloc_font(void)
2836 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2837 ret->gmsize = 1;
2838 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2839 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2840 ret->potm = NULL;
2841 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2842 ret->total_kern_pairs = (DWORD)-1;
2843 ret->kern_pairs = NULL;
2844 list_init(&ret->hfontlist);
2845 list_init(&ret->child_fonts);
2846 return ret;
2849 static void free_font(GdiFont *font)
2851 struct list *cursor, *cursor2;
2852 int i;
2854 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2856 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2857 struct list *first_hfont;
2858 HFONTLIST *hfontlist;
2859 list_remove(cursor);
2860 if(child->font)
2862 first_hfont = list_head(&child->font->hfontlist);
2863 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2864 DeleteObject(hfontlist->hfont);
2865 HeapFree(GetProcessHeap(), 0, hfontlist);
2866 free_font(child->font);
2868 HeapFree(GetProcessHeap(), 0, child);
2871 if (font->ft_face) pFT_Done_Face(font->ft_face);
2872 if (font->mapping) unmap_font_file( font->mapping );
2873 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2874 HeapFree(GetProcessHeap(), 0, font->potm);
2875 HeapFree(GetProcessHeap(), 0, font->name);
2876 for (i = 0; i < font->gmsize; i++)
2877 HeapFree(GetProcessHeap(),0,font->gm[i]);
2878 HeapFree(GetProcessHeap(), 0, font->gm);
2879 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2880 HeapFree(GetProcessHeap(), 0, font);
2884 /*************************************************************
2885 * load_VDMX
2887 * load the vdmx entry for the specified height
2890 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2891 ( ( (FT_ULong)_x4 << 24 ) | \
2892 ( (FT_ULong)_x3 << 16 ) | \
2893 ( (FT_ULong)_x2 << 8 ) | \
2894 (FT_ULong)_x1 )
2896 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2898 typedef struct {
2899 BYTE bCharSet;
2900 BYTE xRatio;
2901 BYTE yStartRatio;
2902 BYTE yEndRatio;
2903 } Ratios;
2905 typedef struct {
2906 WORD recs;
2907 BYTE startsz;
2908 BYTE endsz;
2909 } VDMX_group;
2911 static LONG load_VDMX(GdiFont *font, LONG height)
2913 WORD hdr[3], tmp;
2914 VDMX_group group;
2915 BYTE devXRatio, devYRatio;
2916 USHORT numRecs, numRatios;
2917 DWORD result, offset = -1;
2918 LONG ppem = 0;
2919 int i;
2921 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2923 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2924 return ppem;
2926 /* FIXME: need the real device aspect ratio */
2927 devXRatio = 1;
2928 devYRatio = 1;
2930 numRecs = GET_BE_WORD(hdr[1]);
2931 numRatios = GET_BE_WORD(hdr[2]);
2933 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2934 for(i = 0; i < numRatios; i++) {
2935 Ratios ratio;
2937 offset = (3 * 2) + (i * sizeof(Ratios));
2938 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2939 offset = -1;
2941 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2943 if((ratio.xRatio == 0 &&
2944 ratio.yStartRatio == 0 &&
2945 ratio.yEndRatio == 0) ||
2946 (devXRatio == ratio.xRatio &&
2947 devYRatio >= ratio.yStartRatio &&
2948 devYRatio <= ratio.yEndRatio))
2950 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2951 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2952 offset = GET_BE_WORD(tmp);
2953 break;
2957 if(offset == -1) {
2958 FIXME("No suitable ratio found\n");
2959 return ppem;
2962 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2963 USHORT recs;
2964 BYTE startsz, endsz;
2965 WORD *vTable;
2967 recs = GET_BE_WORD(group.recs);
2968 startsz = group.startsz;
2969 endsz = group.endsz;
2971 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2973 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2974 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2975 if(result == GDI_ERROR) {
2976 FIXME("Failed to retrieve vTable\n");
2977 goto end;
2980 if(height > 0) {
2981 for(i = 0; i < recs; i++) {
2982 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2983 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2984 ppem = GET_BE_WORD(vTable[i * 3]);
2986 if(yMax + -yMin == height) {
2987 font->yMax = yMax;
2988 font->yMin = yMin;
2989 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2990 break;
2992 if(yMax + -yMin > height) {
2993 if(--i < 0) {
2994 ppem = 0;
2995 goto end; /* failed */
2997 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2998 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2999 ppem = GET_BE_WORD(vTable[i * 3]);
3000 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3001 break;
3004 if(!font->yMax) {
3005 ppem = 0;
3006 TRACE("ppem not found for height %d\n", height);
3008 } else {
3009 ppem = -height;
3010 if(ppem < startsz || ppem > endsz)
3011 goto end;
3013 for(i = 0; i < recs; i++) {
3014 USHORT yPelHeight;
3015 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3017 if(yPelHeight > ppem)
3018 break; /* failed */
3020 if(yPelHeight == ppem) {
3021 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3022 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3023 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3024 break;
3028 end:
3029 HeapFree(GetProcessHeap(), 0, vTable);
3032 return ppem;
3035 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3037 if(font->font_desc.hash != fd->hash) return TRUE;
3038 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3039 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3040 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3041 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3044 static void calc_hash(FONT_DESC *pfd)
3046 DWORD hash = 0, *ptr, two_chars;
3047 WORD *pwc;
3048 unsigned int i;
3050 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3051 hash ^= *ptr;
3052 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3053 hash ^= *ptr;
3054 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3055 two_chars = *ptr;
3056 pwc = (WCHAR *)&two_chars;
3057 if(!*pwc) break;
3058 *pwc = toupperW(*pwc);
3059 pwc++;
3060 *pwc = toupperW(*pwc);
3061 hash ^= two_chars;
3062 if(!*pwc) break;
3064 hash ^= !pfd->can_use_bitmap;
3065 pfd->hash = hash;
3066 return;
3069 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
3071 GdiFont *ret;
3072 FONT_DESC fd;
3073 HFONTLIST *hflist;
3074 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3076 fd.lf = *plf;
3077 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
3078 fd.can_use_bitmap = can_use_bitmap;
3079 calc_hash(&fd);
3081 /* try the in-use list */
3082 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3083 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3084 if(!fontcmp(ret, &fd)) {
3085 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3086 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3087 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3088 if(hflist->hfont == hfont)
3089 return ret;
3091 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3092 hflist->hfont = hfont;
3093 list_add_head(&ret->hfontlist, &hflist->entry);
3094 return ret;
3098 /* then the unused list */
3099 font_elem_ptr = list_head(&unused_gdi_font_list);
3100 while(font_elem_ptr) {
3101 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3102 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3103 if(!fontcmp(ret, &fd)) {
3104 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3105 assert(list_empty(&ret->hfontlist));
3106 TRACE("Found %p in unused list\n", ret);
3107 list_remove(&ret->entry);
3108 list_add_head(&gdi_font_list, &ret->entry);
3109 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3110 hflist->hfont = hfont;
3111 list_add_head(&ret->hfontlist, &hflist->entry);
3112 return ret;
3115 return NULL;
3119 /*************************************************************
3120 * create_child_font_list
3122 static BOOL create_child_font_list(GdiFont *font)
3124 BOOL ret = FALSE;
3125 SYSTEM_LINKS *font_link;
3126 CHILD_FONT *font_link_entry, *new_child;
3128 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3130 if(!strcmpW(font_link->font_name, font->name))
3132 TRACE("found entry in system list\n");
3133 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3135 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3136 new_child->face = font_link_entry->face;
3137 new_child->font = NULL;
3138 list_add_tail(&font->child_fonts, &new_child->entry);
3139 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3141 ret = TRUE;
3142 break;
3146 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3147 * Sans Serif. This is how asian windows get default fallbacks for fonts
3149 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3150 font->charset != OEM_CHARSET &&
3151 strcmpW(font->name,szDefaultFallbackLink) != 0)
3152 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3154 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3156 TRACE("found entry in default fallback list\n");
3157 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3159 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3160 new_child->face = font_link_entry->face;
3161 new_child->font = NULL;
3162 list_add_tail(&font->child_fonts, &new_child->entry);
3163 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3165 ret = TRUE;
3166 break;
3170 return ret;
3173 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3175 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3177 if (pFT_Set_Charmap)
3179 FT_Int i;
3180 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3182 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3184 for (i = 0; i < ft_face->num_charmaps; i++)
3186 if (ft_face->charmaps[i]->encoding == encoding)
3188 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3189 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3191 switch (ft_face->charmaps[i]->platform_id)
3193 default:
3194 cmap_def = ft_face->charmaps[i];
3195 break;
3196 case 0: /* Apple Unicode */
3197 cmap0 = ft_face->charmaps[i];
3198 break;
3199 case 1: /* Macintosh */
3200 cmap1 = ft_face->charmaps[i];
3201 break;
3202 case 2: /* ISO */
3203 cmap2 = ft_face->charmaps[i];
3204 break;
3205 case 3: /* Microsoft */
3206 cmap3 = ft_face->charmaps[i];
3207 break;
3211 if (cmap3) /* prefer Microsoft cmap table */
3212 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3213 else if (cmap1)
3214 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3215 else if (cmap2)
3216 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3217 else if (cmap0)
3218 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3219 else if (cmap_def)
3220 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3222 return ft_err == FT_Err_Ok;
3225 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3228 /*************************************************************
3229 * WineEngCreateFontInstance
3232 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3234 GdiFont *ret;
3235 Face *face, *best, *best_bitmap;
3236 Family *family, *last_resort_family;
3237 struct list *family_elem_ptr, *face_elem_ptr;
3238 INT height, width = 0;
3239 unsigned int score = 0, new_score;
3240 signed int diff = 0, newdiff;
3241 BOOL bd, it, can_use_bitmap;
3242 LOGFONTW lf;
3243 CHARSETINFO csi;
3244 HFONTLIST *hflist;
3245 FontSubst *psub = NULL;
3247 EnterCriticalSection( &freetype_cs );
3249 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3251 struct list *first_hfont = list_head(&ret->hfontlist);
3252 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3253 if(hflist->hfont == hfont)
3255 LeaveCriticalSection( &freetype_cs );
3256 return ret;
3260 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3262 LeaveCriticalSection( &freetype_cs );
3263 return NULL;
3265 lf.lfWidth = abs(lf.lfWidth);
3267 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3269 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3270 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3271 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3272 lf.lfEscapement);
3274 /* check the cache first */
3275 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3276 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3277 LeaveCriticalSection( &freetype_cs );
3278 return ret;
3281 TRACE("not in cache\n");
3282 if(list_empty(&font_list)) /* No fonts installed */
3284 TRACE("No fonts installed\n");
3285 LeaveCriticalSection( &freetype_cs );
3286 return NULL;
3288 if(!have_installed_roman_font)
3290 TRACE("No roman font installed\n");
3291 LeaveCriticalSection( &freetype_cs );
3292 return NULL;
3295 ret = alloc_font();
3297 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3298 ret->font_desc.lf = lf;
3299 ret->font_desc.can_use_bitmap = can_use_bitmap;
3300 calc_hash(&ret->font_desc);
3301 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3302 hflist->hfont = hfont;
3303 list_add_head(&ret->hfontlist, &hflist->entry);
3306 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3307 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3308 original value lfCharSet. Note this is a special case for
3309 Symbol and doesn't happen at least for "Wingdings*" */
3311 if(!strcmpiW(lf.lfFaceName, SymbolW))
3312 lf.lfCharSet = SYMBOL_CHARSET;
3314 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3315 switch(lf.lfCharSet) {
3316 case DEFAULT_CHARSET:
3317 csi.fs.fsCsb[0] = 0;
3318 break;
3319 default:
3320 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3321 csi.fs.fsCsb[0] = 0;
3322 break;
3326 family = NULL;
3327 if(lf.lfFaceName[0] != '\0') {
3328 SYSTEM_LINKS *font_link;
3329 CHILD_FONT *font_link_entry;
3330 LPWSTR FaceName = lf.lfFaceName;
3333 * Check for a leading '@' this signals that the font is being
3334 * requested in tategaki mode (vertical writing substitution) but
3335 * does not affect the fontface that is to be selected.
3337 if (lf.lfFaceName[0]=='@')
3338 FaceName = &lf.lfFaceName[1];
3340 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3342 if(psub) {
3343 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3344 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3345 if (psub->to.charset != -1)
3346 lf.lfCharSet = psub->to.charset;
3349 /* We want a match on name and charset or just name if
3350 charset was DEFAULT_CHARSET. If the latter then
3351 we fixup the returned charset later in get_nearest_charset
3352 where we'll either use the charset of the current ansi codepage
3353 or if that's unavailable the first charset that the font supports.
3355 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3356 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3357 if (!strcmpiW(family->FamilyName, FaceName) ||
3358 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3360 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3361 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3362 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3363 if(face->scalable || can_use_bitmap)
3364 goto found;
3370 * Try check the SystemLink list first for a replacement font.
3371 * We may find good replacements there.
3373 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3375 if(!strcmpiW(font_link->font_name, FaceName))
3377 TRACE("found entry in system list\n");
3378 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3380 face = font_link_entry->face;
3381 family = face->family;
3382 if(csi.fs.fsCsb[0] &
3383 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3385 if(face->scalable || can_use_bitmap)
3386 goto found;
3393 psub = NULL; /* substitution is no more relevant */
3395 /* If requested charset was DEFAULT_CHARSET then try using charset
3396 corresponding to the current ansi codepage */
3397 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3399 INT acp = GetACP();
3400 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3401 FIXME("TCI failed on codepage %d\n", acp);
3402 csi.fs.fsCsb[0] = 0;
3403 } else
3404 lf.lfCharSet = csi.ciCharset;
3407 /* Face families are in the top 4 bits of lfPitchAndFamily,
3408 so mask with 0xF0 before testing */
3410 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3411 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3412 strcpyW(lf.lfFaceName, defFixed);
3413 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3414 strcpyW(lf.lfFaceName, defSerif);
3415 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3416 strcpyW(lf.lfFaceName, defSans);
3417 else
3418 strcpyW(lf.lfFaceName, defSans);
3419 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3420 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3421 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3422 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3423 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3424 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3425 if(face->scalable || can_use_bitmap)
3426 goto found;
3431 last_resort_family = NULL;
3432 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3433 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3434 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3435 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3436 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3437 if(face->scalable)
3438 goto found;
3439 if(can_use_bitmap && !last_resort_family)
3440 last_resort_family = family;
3445 if(last_resort_family) {
3446 family = last_resort_family;
3447 csi.fs.fsCsb[0] = 0;
3448 goto found;
3451 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3452 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3453 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3454 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3455 if(face->scalable) {
3456 csi.fs.fsCsb[0] = 0;
3457 WARN("just using first face for now\n");
3458 goto found;
3460 if(can_use_bitmap && !last_resort_family)
3461 last_resort_family = family;
3464 if(!last_resort_family) {
3465 FIXME("can't find a single appropriate font - bailing\n");
3466 free_font(ret);
3467 LeaveCriticalSection( &freetype_cs );
3468 return NULL;
3471 WARN("could only find a bitmap font - this will probably look awful!\n");
3472 family = last_resort_family;
3473 csi.fs.fsCsb[0] = 0;
3475 found:
3476 it = lf.lfItalic ? 1 : 0;
3477 bd = lf.lfWeight > 550 ? 1 : 0;
3479 height = GDI_ROUND( (double)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3480 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3482 face = best = best_bitmap = NULL;
3483 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3485 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3487 BOOL italic, bold;
3489 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3490 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3491 new_score = (italic ^ it) + (bold ^ bd);
3492 if(!best || new_score <= score)
3494 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3495 italic, bold, it, bd);
3496 score = new_score;
3497 best = face;
3498 if(best->scalable && score == 0) break;
3499 if(!best->scalable)
3501 if(height > 0)
3502 newdiff = height - (signed int)(best->size.height);
3503 else
3504 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3505 if(!best_bitmap || new_score < score ||
3506 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3508 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3509 diff = newdiff;
3510 best_bitmap = best;
3511 if(score == 0 && diff == 0) break;
3517 if(best)
3518 face = best->scalable ? best : best_bitmap;
3519 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3520 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3522 ret->fs = face->fs;
3524 if(csi.fs.fsCsb[0]) {
3525 ret->charset = lf.lfCharSet;
3526 ret->codepage = csi.ciACP;
3528 else
3529 ret->charset = get_nearest_charset(face, &ret->codepage);
3531 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3532 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3534 ret->aveWidth = height ? lf.lfWidth : 0;
3536 if(!face->scalable) {
3537 /* Windows uses integer scaling factors for bitmap fonts */
3538 INT scale, scaled_height;
3540 if (height != 0) height = diff;
3541 height += face->size.height;
3543 scale = (height + face->size.height - 1) / face->size.height;
3544 scaled_height = scale * face->size.height;
3545 /* XP allows not more than 10% deviation */
3546 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3547 ret->scale_y = scale;
3549 width = face->size.x_ppem >> 6;
3550 height = face->size.y_ppem >> 6;
3552 else
3553 ret->scale_y = 1.0;
3554 TRACE("font scale y: %f\n", ret->scale_y);
3556 ret->ft_face = OpenFontFace(ret, face, width, height);
3558 if (!ret->ft_face)
3560 free_font( ret );
3561 LeaveCriticalSection( &freetype_cs );
3562 return 0;
3565 ret->ntmFlags = face->ntmFlags;
3567 if (ret->charset == SYMBOL_CHARSET &&
3568 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3569 /* No ops */
3571 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3572 /* No ops */
3574 else {
3575 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3578 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3579 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3580 ret->underline = lf.lfUnderline ? 0xff : 0;
3581 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3582 create_child_font_list(ret);
3584 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3586 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3587 if (length != GDI_ERROR)
3589 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3590 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3591 TRACE("Loaded GSUB table of %i bytes\n",length);
3595 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3597 list_add_head(&gdi_font_list, &ret->entry);
3598 LeaveCriticalSection( &freetype_cs );
3599 return ret;
3602 static void dump_gdi_font_list(void)
3604 GdiFont *gdiFont;
3605 struct list *elem_ptr;
3607 TRACE("---------- gdiFont Cache ----------\n");
3608 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3609 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3610 TRACE("gdiFont=%p %s %d\n",
3611 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3614 TRACE("---------- Unused gdiFont Cache ----------\n");
3615 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3616 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3617 TRACE("gdiFont=%p %s %d\n",
3618 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3622 /*************************************************************
3623 * WineEngDestroyFontInstance
3625 * free the gdiFont associated with this handle
3628 BOOL WineEngDestroyFontInstance(HFONT handle)
3630 GdiFont *gdiFont;
3631 HFONTLIST *hflist;
3632 BOOL ret = FALSE;
3633 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3634 int i = 0;
3636 EnterCriticalSection( &freetype_cs );
3638 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3640 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3641 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3642 if(hflist->hfont == handle)
3644 TRACE("removing child font %p from child list\n", gdiFont);
3645 list_remove(&gdiFont->entry);
3646 LeaveCriticalSection( &freetype_cs );
3647 return TRUE;
3651 TRACE("destroying hfont=%p\n", handle);
3652 if(TRACE_ON(font))
3653 dump_gdi_font_list();
3655 font_elem_ptr = list_head(&gdi_font_list);
3656 while(font_elem_ptr) {
3657 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3658 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3660 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3661 while(hfontlist_elem_ptr) {
3662 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3663 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3664 if(hflist->hfont == handle) {
3665 list_remove(&hflist->entry);
3666 HeapFree(GetProcessHeap(), 0, hflist);
3667 ret = TRUE;
3670 if(list_empty(&gdiFont->hfontlist)) {
3671 TRACE("Moving to Unused list\n");
3672 list_remove(&gdiFont->entry);
3673 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3678 font_elem_ptr = list_head(&unused_gdi_font_list);
3679 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3680 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3681 while(font_elem_ptr) {
3682 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3683 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3684 TRACE("freeing %p\n", gdiFont);
3685 list_remove(&gdiFont->entry);
3686 free_font(gdiFont);
3688 LeaveCriticalSection( &freetype_cs );
3689 return ret;
3692 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3693 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3695 GdiFont *font;
3696 LONG width, height;
3698 if (face->cached_enum_data)
3700 TRACE("Cached\n");
3701 *pelf = face->cached_enum_data->elf;
3702 *pntm = face->cached_enum_data->ntm;
3703 *ptype = face->cached_enum_data->type;
3704 return;
3707 font = alloc_font();
3709 if(face->scalable) {
3710 height = -2048; /* 2048 is the most common em size */
3711 width = 0;
3712 } else {
3713 height = face->size.y_ppem >> 6;
3714 width = face->size.x_ppem >> 6;
3716 font->scale_y = 1.0;
3718 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3720 free_font(font);
3721 return;
3724 font->name = strdupW(face->family->FamilyName);
3725 font->ntmFlags = face->ntmFlags;
3727 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3729 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3731 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3733 lstrcpynW(pelf->elfLogFont.lfFaceName,
3734 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3735 LF_FACESIZE);
3736 lstrcpynW(pelf->elfFullName,
3737 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3738 LF_FULLFACESIZE);
3739 lstrcpynW(pelf->elfStyle,
3740 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3741 LF_FACESIZE);
3743 else
3745 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3747 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3749 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3750 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3751 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3754 pntm->ntmTm.ntmFlags = face->ntmFlags;
3755 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3756 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3757 pntm->ntmFontSig = face->fs;
3759 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3761 pelf->elfLogFont.lfEscapement = 0;
3762 pelf->elfLogFont.lfOrientation = 0;
3763 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3764 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3765 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3766 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3767 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3768 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3769 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3770 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3771 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3772 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3773 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3775 *ptype = 0;
3776 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3777 *ptype |= TRUETYPE_FONTTYPE;
3778 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3779 *ptype |= DEVICE_FONTTYPE;
3780 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3781 *ptype |= RASTER_FONTTYPE;
3783 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3784 if (face->cached_enum_data)
3786 face->cached_enum_data->elf = *pelf;
3787 face->cached_enum_data->ntm = *pntm;
3788 face->cached_enum_data->type = *ptype;
3791 free_font(font);
3794 /*************************************************************
3795 * WineEngEnumFonts
3798 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3800 Family *family;
3801 Face *face;
3802 struct list *family_elem_ptr, *face_elem_ptr;
3803 ENUMLOGFONTEXW elf;
3804 NEWTEXTMETRICEXW ntm;
3805 DWORD type;
3806 FONTSIGNATURE fs;
3807 CHARSETINFO csi;
3808 LOGFONTW lf;
3809 int i;
3811 if (!plf)
3813 lf.lfCharSet = DEFAULT_CHARSET;
3814 lf.lfPitchAndFamily = 0;
3815 lf.lfFaceName[0] = 0;
3816 plf = &lf;
3819 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3821 EnterCriticalSection( &freetype_cs );
3822 if(plf->lfFaceName[0]) {
3823 FontSubst *psub;
3824 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3826 if(psub) {
3827 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3828 debugstr_w(psub->to.name));
3829 lf = *plf;
3830 strcpyW(lf.lfFaceName, psub->to.name);
3831 plf = &lf;
3834 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3835 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3836 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3837 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3838 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3839 GetEnumStructs(face, &elf, &ntm, &type);
3840 for(i = 0; i < 32; i++) {
3841 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3842 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3843 strcpyW(elf.elfScript, OEM_DOSW);
3844 i = 32; /* break out of loop */
3845 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3846 continue;
3847 else {
3848 fs.fsCsb[0] = 1L << i;
3849 fs.fsCsb[1] = 0;
3850 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3851 TCI_SRCFONTSIG))
3852 csi.ciCharset = DEFAULT_CHARSET;
3853 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3854 if(csi.ciCharset != DEFAULT_CHARSET) {
3855 elf.elfLogFont.lfCharSet =
3856 ntm.ntmTm.tmCharSet = csi.ciCharset;
3857 if(ElfScriptsW[i])
3858 strcpyW(elf.elfScript, ElfScriptsW[i]);
3859 else
3860 FIXME("Unknown elfscript for bit %d\n", i);
3863 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3864 debugstr_w(elf.elfLogFont.lfFaceName),
3865 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3866 csi.ciCharset, type, debugstr_w(elf.elfScript),
3867 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3868 ntm.ntmTm.ntmFlags);
3869 /* release section before callback (FIXME) */
3870 LeaveCriticalSection( &freetype_cs );
3871 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3872 EnterCriticalSection( &freetype_cs );
3877 } else {
3878 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3879 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3880 face_elem_ptr = list_head(&family->faces);
3881 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3882 GetEnumStructs(face, &elf, &ntm, &type);
3883 for(i = 0; i < 32; i++) {
3884 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3885 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3886 strcpyW(elf.elfScript, OEM_DOSW);
3887 i = 32; /* break out of loop */
3888 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3889 continue;
3890 else {
3891 fs.fsCsb[0] = 1L << i;
3892 fs.fsCsb[1] = 0;
3893 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3894 TCI_SRCFONTSIG))
3895 csi.ciCharset = DEFAULT_CHARSET;
3896 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3897 if(csi.ciCharset != DEFAULT_CHARSET) {
3898 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3899 csi.ciCharset;
3900 if(ElfScriptsW[i])
3901 strcpyW(elf.elfScript, ElfScriptsW[i]);
3902 else
3903 FIXME("Unknown elfscript for bit %d\n", i);
3906 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3907 debugstr_w(elf.elfLogFont.lfFaceName),
3908 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3909 csi.ciCharset, type, debugstr_w(elf.elfScript),
3910 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3911 ntm.ntmTm.ntmFlags);
3912 /* release section before callback (FIXME) */
3913 LeaveCriticalSection( &freetype_cs );
3914 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3915 EnterCriticalSection( &freetype_cs );
3919 LeaveCriticalSection( &freetype_cs );
3920 return 1;
3923 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3925 pt->x.value = vec->x >> 6;
3926 pt->x.fract = (vec->x & 0x3f) << 10;
3927 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3928 pt->y.value = vec->y >> 6;
3929 pt->y.fract = (vec->y & 0x3f) << 10;
3930 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3931 return;
3934 /***************************************************
3935 * According to the MSDN documentation on WideCharToMultiByte,
3936 * certain codepages cannot set the default_used parameter.
3937 * This returns TRUE if the codepage can set that parameter, false else
3938 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3940 static BOOL codepage_sets_default_used(UINT codepage)
3942 switch (codepage)
3944 case CP_UTF7:
3945 case CP_UTF8:
3946 case CP_SYMBOL:
3947 return FALSE;
3948 default:
3949 return TRUE;
3954 * GSUB Table handling functions
3957 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3959 const GSUB_CoverageFormat1* cf1;
3961 cf1 = (GSUB_CoverageFormat1*)table;
3963 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3965 int count = GET_BE_WORD(cf1->GlyphCount);
3966 int i;
3967 TRACE("Coverage Format 1, %i glyphs\n",count);
3968 for (i = 0; i < count; i++)
3969 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3970 return i;
3971 return -1;
3973 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3975 const GSUB_CoverageFormat2* cf2;
3976 int i;
3977 int count;
3978 cf2 = (GSUB_CoverageFormat2*)cf1;
3980 count = GET_BE_WORD(cf2->RangeCount);
3981 TRACE("Coverage Format 2, %i ranges\n",count);
3982 for (i = 0; i < count; i++)
3984 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3985 return -1;
3986 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3987 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3989 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3990 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3993 return -1;
3995 else
3996 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3998 return -1;
4001 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4003 const GSUB_ScriptList *script;
4004 const GSUB_Script *deflt = NULL;
4005 int i;
4006 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4008 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4009 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4011 const GSUB_Script *scr;
4012 int offset;
4014 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4015 scr = (GSUB_Script*)((LPBYTE)script + offset);
4017 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4018 return scr;
4019 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4020 deflt = scr;
4022 return deflt;
4025 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4027 int i;
4028 int offset;
4029 const GSUB_LangSys *Lang;
4031 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4033 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4035 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4036 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4038 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4039 return Lang;
4041 offset = GET_BE_WORD(script->DefaultLangSys);
4042 if (offset)
4044 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4045 return Lang;
4047 return NULL;
4050 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4052 int i;
4053 const GSUB_FeatureList *feature;
4054 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4056 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4057 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4059 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4060 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4062 const GSUB_Feature *feat;
4063 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4064 return feat;
4067 return NULL;
4070 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4072 int i;
4073 int offset;
4074 const GSUB_LookupList *lookup;
4075 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4077 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4078 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4080 const GSUB_LookupTable *look;
4081 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4082 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4083 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4084 if (GET_BE_WORD(look->LookupType) != 1)
4085 FIXME("We only handle SubType 1\n");
4086 else
4088 int j;
4090 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4092 const GSUB_SingleSubstFormat1 *ssf1;
4093 offset = GET_BE_WORD(look->SubTable[j]);
4094 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4095 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4097 int offset = GET_BE_WORD(ssf1->Coverage);
4098 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4099 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4101 TRACE(" Glyph 0x%x ->",glyph);
4102 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4103 TRACE(" 0x%x\n",glyph);
4106 else
4108 const GSUB_SingleSubstFormat2 *ssf2;
4109 INT index;
4110 INT offset;
4112 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4113 offset = GET_BE_WORD(ssf1->Coverage);
4114 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4115 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4116 TRACE(" Coverage index %i\n",index);
4117 if (index != -1)
4119 TRACE(" Glyph is 0x%x ->",glyph);
4120 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4121 TRACE("0x%x\n",glyph);
4127 return glyph;
4130 static const char* get_opentype_script(const GdiFont *font)
4133 * I am not sure if this is the correct way to generate our script tag
4136 switch (font->charset)
4138 case ANSI_CHARSET: return "latn";
4139 case BALTIC_CHARSET: return "latn"; /* ?? */
4140 case CHINESEBIG5_CHARSET: return "hani";
4141 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4142 case GB2312_CHARSET: return "hani";
4143 case GREEK_CHARSET: return "grek";
4144 case HANGUL_CHARSET: return "hang";
4145 case RUSSIAN_CHARSET: return "cyrl";
4146 case SHIFTJIS_CHARSET: return "kana";
4147 case TURKISH_CHARSET: return "latn"; /* ?? */
4148 case VIETNAMESE_CHARSET: return "latn";
4149 case JOHAB_CHARSET: return "latn"; /* ?? */
4150 case ARABIC_CHARSET: return "arab";
4151 case HEBREW_CHARSET: return "hebr";
4152 case THAI_CHARSET: return "thai";
4153 default: return "latn";
4157 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4159 const GSUB_Header *header;
4160 const GSUB_Script *script;
4161 const GSUB_LangSys *language;
4162 const GSUB_Feature *feature;
4164 if (!font->GSUB_Table)
4165 return glyph;
4167 header = font->GSUB_Table;
4169 script = GSUB_get_script_table(header, get_opentype_script(font));
4170 if (!script)
4172 TRACE("Script not found\n");
4173 return glyph;
4175 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4176 if (!language)
4178 TRACE("Language not found\n");
4179 return glyph;
4181 feature = GSUB_get_feature(header, language, "vrt2");
4182 if (!feature)
4183 feature = GSUB_get_feature(header, language, "vert");
4184 if (!feature)
4186 TRACE("vrt2/vert feature not found\n");
4187 return glyph;
4189 return GSUB_apply_feature(header, feature, glyph);
4192 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4194 FT_UInt glyphId;
4196 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4197 WCHAR wc = (WCHAR)glyph;
4198 BOOL default_used;
4199 BOOL *default_used_pointer;
4200 FT_UInt ret;
4201 char buf;
4202 default_used_pointer = NULL;
4203 default_used = FALSE;
4204 if (codepage_sets_default_used(font->codepage))
4205 default_used_pointer = &default_used;
4206 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4207 ret = 0;
4208 else
4209 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4210 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4211 return get_GSUB_vert_glyph(font,ret);
4214 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4215 glyph = glyph + 0xf000;
4216 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4217 return get_GSUB_vert_glyph(font,glyphId);
4220 /*************************************************************
4221 * WineEngGetGlyphIndices
4224 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4225 LPWORD pgi, DWORD flags)
4227 int i;
4228 int default_char = -1;
4230 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4232 for(i = 0; i < count; i++)
4234 pgi[i] = get_glyph_index(font, lpstr[i]);
4235 if (pgi[i] == 0)
4237 if (default_char == -1)
4239 if (FT_IS_SFNT(font->ft_face))
4241 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4242 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4244 else
4246 TEXTMETRICW textm;
4247 WineEngGetTextMetrics(font, &textm);
4248 default_char = textm.tmDefaultChar;
4251 pgi[i] = default_char;
4254 return count;
4257 /*************************************************************
4258 * WineEngGetGlyphOutline
4260 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4261 * except that the first parameter is the HWINEENGFONT of the font in
4262 * question rather than an HDC.
4265 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4266 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4267 const MAT2* lpmat)
4269 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4270 FT_Face ft_face = incoming_font->ft_face;
4271 GdiFont *font = incoming_font;
4272 FT_UInt glyph_index;
4273 DWORD width, height, pitch, needed = 0;
4274 FT_Bitmap ft_bitmap;
4275 FT_Error err;
4276 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4277 FT_Angle angle = 0;
4278 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4279 float widthRatio = 1.0;
4280 FT_Matrix transMat = identityMat;
4281 BOOL needsTransform = FALSE;
4282 BOOL tategaki = (font->GSUB_Table != NULL);
4283 UINT original_index;
4286 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4287 buflen, buf, lpmat);
4289 EnterCriticalSection( &freetype_cs );
4291 if(format & GGO_GLYPH_INDEX) {
4292 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4293 original_index = glyph;
4294 format &= ~GGO_GLYPH_INDEX;
4295 } else {
4296 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4297 ft_face = font->ft_face;
4298 original_index = glyph_index;
4301 /* tategaki never appears to happen to lower glyph index */
4302 if (glyph_index < TATEGAKI_LOWER_BOUND )
4303 tategaki = FALSE;
4305 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4306 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4307 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4308 font->gmsize * sizeof(GM*));
4309 } else {
4310 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4311 *lpgm = FONT_GM(font,original_index)->gm;
4312 LeaveCriticalSection( &freetype_cs );
4313 return 1; /* FIXME */
4317 if (!font->gm[original_index / GM_BLOCK_SIZE])
4318 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4320 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4321 load_flags |= FT_LOAD_NO_BITMAP;
4323 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4325 if(err) {
4326 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4327 LeaveCriticalSection( &freetype_cs );
4328 return GDI_ERROR;
4331 /* Scaling factor */
4332 if (font->aveWidth && font->potm)
4334 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4335 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4337 else
4338 widthRatio = font->scale_y;
4340 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4341 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4343 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4344 lsb = left >> 6;
4345 bbx = (right - left) >> 6;
4347 /* Scaling transform */
4348 if(font->aveWidth) {
4349 FT_Matrix scaleMat;
4350 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4351 scaleMat.xy = 0;
4352 scaleMat.yx = 0;
4353 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4355 pFT_Matrix_Multiply(&scaleMat, &transMat);
4356 needsTransform = TRUE;
4359 /* Slant transform */
4360 if (font->fake_italic) {
4361 FT_Matrix slantMat;
4363 slantMat.xx = (1 << 16);
4364 slantMat.xy = ((1 << 16) >> 2);
4365 slantMat.yx = 0;
4366 slantMat.yy = (1 << 16);
4367 pFT_Matrix_Multiply(&slantMat, &transMat);
4368 needsTransform = TRUE;
4371 /* Rotation transform */
4372 if(font->orientation && !tategaki) {
4373 FT_Matrix rotationMat;
4374 FT_Vector vecAngle;
4375 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4376 pFT_Vector_Unit(&vecAngle, angle);
4377 rotationMat.xx = vecAngle.x;
4378 rotationMat.xy = -vecAngle.y;
4379 rotationMat.yx = -rotationMat.xy;
4380 rotationMat.yy = rotationMat.xx;
4382 pFT_Matrix_Multiply(&rotationMat, &transMat);
4383 needsTransform = TRUE;
4386 /* Extra transformation specified by caller */
4387 if (lpmat) {
4388 FT_Matrix extraMat;
4389 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4390 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4391 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4392 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4393 pFT_Matrix_Multiply(&extraMat, &transMat);
4394 needsTransform = TRUE;
4397 if(!needsTransform) {
4398 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4399 bottom = (ft_face->glyph->metrics.horiBearingY -
4400 ft_face->glyph->metrics.height) & -64;
4401 lpgm->gmCellIncX = adv;
4402 lpgm->gmCellIncY = 0;
4403 } else {
4404 INT xc, yc;
4405 FT_Vector vec;
4406 for(xc = 0; xc < 2; xc++) {
4407 for(yc = 0; yc < 2; yc++) {
4408 vec.x = (ft_face->glyph->metrics.horiBearingX +
4409 xc * ft_face->glyph->metrics.width);
4410 vec.y = ft_face->glyph->metrics.horiBearingY -
4411 yc * ft_face->glyph->metrics.height;
4412 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4413 pFT_Vector_Transform(&vec, &transMat);
4414 if(xc == 0 && yc == 0) {
4415 left = right = vec.x;
4416 top = bottom = vec.y;
4417 } else {
4418 if(vec.x < left) left = vec.x;
4419 else if(vec.x > right) right = vec.x;
4420 if(vec.y < bottom) bottom = vec.y;
4421 else if(vec.y > top) top = vec.y;
4425 left = left & -64;
4426 right = (right + 63) & -64;
4427 bottom = bottom & -64;
4428 top = (top + 63) & -64;
4430 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4431 vec.x = ft_face->glyph->metrics.horiAdvance;
4432 vec.y = 0;
4433 pFT_Vector_Transform(&vec, &transMat);
4434 lpgm->gmCellIncX = (vec.x+63) >> 6;
4435 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4437 lpgm->gmBlackBoxX = (right - left) >> 6;
4438 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4439 lpgm->gmptGlyphOrigin.x = left >> 6;
4440 lpgm->gmptGlyphOrigin.y = top >> 6;
4442 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4444 FONT_GM(font,original_index)->gm = *lpgm;
4445 FONT_GM(font,original_index)->adv = adv;
4446 FONT_GM(font,original_index)->lsb = lsb;
4447 FONT_GM(font,original_index)->bbx = bbx;
4448 FONT_GM(font,original_index)->init = TRUE;
4451 if(format == GGO_METRICS)
4453 LeaveCriticalSection( &freetype_cs );
4454 return 1; /* FIXME */
4457 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4458 TRACE("loaded a bitmap\n");
4459 LeaveCriticalSection( &freetype_cs );
4460 return GDI_ERROR;
4463 switch(format) {
4464 case GGO_BITMAP:
4465 width = lpgm->gmBlackBoxX;
4466 height = lpgm->gmBlackBoxY;
4467 pitch = ((width + 31) >> 5) << 2;
4468 needed = pitch * height;
4470 if(!buf || !buflen) break;
4472 switch(ft_face->glyph->format) {
4473 case ft_glyph_format_bitmap:
4475 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4476 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4477 INT h = ft_face->glyph->bitmap.rows;
4478 while(h--) {
4479 memcpy(dst, src, w);
4480 src += ft_face->glyph->bitmap.pitch;
4481 dst += pitch;
4483 break;
4486 case ft_glyph_format_outline:
4487 ft_bitmap.width = width;
4488 ft_bitmap.rows = height;
4489 ft_bitmap.pitch = pitch;
4490 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4491 ft_bitmap.buffer = buf;
4493 if(needsTransform) {
4494 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4497 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4499 /* Note: FreeType will only set 'black' bits for us. */
4500 memset(buf, 0, needed);
4501 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4502 break;
4504 default:
4505 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4506 LeaveCriticalSection( &freetype_cs );
4507 return GDI_ERROR;
4509 break;
4511 case GGO_GRAY2_BITMAP:
4512 case GGO_GRAY4_BITMAP:
4513 case GGO_GRAY8_BITMAP:
4514 case WINE_GGO_GRAY16_BITMAP:
4516 unsigned int mult, row, col;
4517 BYTE *start, *ptr;
4519 width = lpgm->gmBlackBoxX;
4520 height = lpgm->gmBlackBoxY;
4521 pitch = (width + 3) / 4 * 4;
4522 needed = pitch * height;
4524 if(!buf || !buflen) break;
4526 switch(ft_face->glyph->format) {
4527 case ft_glyph_format_bitmap:
4529 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4530 INT h = ft_face->glyph->bitmap.rows;
4531 INT x;
4532 while(h--) {
4533 for(x = 0; x < pitch; x++)
4535 if(x < ft_face->glyph->bitmap.width)
4536 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4537 else
4538 dst[x] = 0;
4540 src += ft_face->glyph->bitmap.pitch;
4541 dst += pitch;
4543 LeaveCriticalSection( &freetype_cs );
4544 return needed;
4546 case ft_glyph_format_outline:
4548 ft_bitmap.width = width;
4549 ft_bitmap.rows = height;
4550 ft_bitmap.pitch = pitch;
4551 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4552 ft_bitmap.buffer = buf;
4554 if(needsTransform)
4555 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4557 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4559 memset(ft_bitmap.buffer, 0, buflen);
4561 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4563 if(format == GGO_GRAY2_BITMAP)
4564 mult = 4;
4565 else if(format == GGO_GRAY4_BITMAP)
4566 mult = 16;
4567 else if(format == GGO_GRAY8_BITMAP)
4568 mult = 64;
4569 else /* format == WINE_GGO_GRAY16_BITMAP */
4571 LeaveCriticalSection( &freetype_cs );
4572 return needed;
4574 break;
4576 default:
4577 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4578 LeaveCriticalSection( &freetype_cs );
4579 return GDI_ERROR;
4582 start = buf;
4583 for(row = 0; row < height; row++) {
4584 ptr = start;
4585 for(col = 0; col < width; col++, ptr++) {
4586 *ptr = (((int)*ptr) * mult + 128) / 256;
4588 start += pitch;
4590 break;
4593 case GGO_NATIVE:
4595 int contour, point = 0, first_pt;
4596 FT_Outline *outline = &ft_face->glyph->outline;
4597 TTPOLYGONHEADER *pph;
4598 TTPOLYCURVE *ppc;
4599 DWORD pph_start, cpfx, type;
4601 if(buflen == 0) buf = NULL;
4603 if (needsTransform && buf) {
4604 pFT_Outline_Transform(outline, &transMat);
4607 for(contour = 0; contour < outline->n_contours; contour++) {
4608 pph_start = needed;
4609 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4610 first_pt = point;
4611 if(buf) {
4612 pph->dwType = TT_POLYGON_TYPE;
4613 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4615 needed += sizeof(*pph);
4616 point++;
4617 while(point <= outline->contours[contour]) {
4618 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4619 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4620 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4621 cpfx = 0;
4622 do {
4623 if(buf)
4624 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4625 cpfx++;
4626 point++;
4627 } while(point <= outline->contours[contour] &&
4628 (outline->tags[point] & FT_Curve_Tag_On) ==
4629 (outline->tags[point-1] & FT_Curve_Tag_On));
4630 /* At the end of a contour Windows adds the start point, but
4631 only for Beziers */
4632 if(point > outline->contours[contour] &&
4633 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4634 if(buf)
4635 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4636 cpfx++;
4637 } else if(point <= outline->contours[contour] &&
4638 outline->tags[point] & FT_Curve_Tag_On) {
4639 /* add closing pt for bezier */
4640 if(buf)
4641 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4642 cpfx++;
4643 point++;
4645 if(buf) {
4646 ppc->wType = type;
4647 ppc->cpfx = cpfx;
4649 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4651 if(buf)
4652 pph->cb = needed - pph_start;
4654 break;
4656 case GGO_BEZIER:
4658 /* Convert the quadratic Beziers to cubic Beziers.
4659 The parametric eqn for a cubic Bezier is, from PLRM:
4660 r(t) = at^3 + bt^2 + ct + r0
4661 with the control points:
4662 r1 = r0 + c/3
4663 r2 = r1 + (c + b)/3
4664 r3 = r0 + c + b + a
4666 A quadratic Beizer has the form:
4667 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4669 So equating powers of t leads to:
4670 r1 = 2/3 p1 + 1/3 p0
4671 r2 = 2/3 p1 + 1/3 p2
4672 and of course r0 = p0, r3 = p2
4675 int contour, point = 0, first_pt;
4676 FT_Outline *outline = &ft_face->glyph->outline;
4677 TTPOLYGONHEADER *pph;
4678 TTPOLYCURVE *ppc;
4679 DWORD pph_start, cpfx, type;
4680 FT_Vector cubic_control[4];
4681 if(buflen == 0) buf = NULL;
4683 if (needsTransform && buf) {
4684 pFT_Outline_Transform(outline, &transMat);
4687 for(contour = 0; contour < outline->n_contours; contour++) {
4688 pph_start = needed;
4689 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4690 first_pt = point;
4691 if(buf) {
4692 pph->dwType = TT_POLYGON_TYPE;
4693 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4695 needed += sizeof(*pph);
4696 point++;
4697 while(point <= outline->contours[contour]) {
4698 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4699 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4700 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4701 cpfx = 0;
4702 do {
4703 if(type == TT_PRIM_LINE) {
4704 if(buf)
4705 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4706 cpfx++;
4707 point++;
4708 } else {
4709 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4710 so cpfx = 3n */
4712 /* FIXME: Possible optimization in endpoint calculation
4713 if there are two consecutive curves */
4714 cubic_control[0] = outline->points[point-1];
4715 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4716 cubic_control[0].x += outline->points[point].x + 1;
4717 cubic_control[0].y += outline->points[point].y + 1;
4718 cubic_control[0].x >>= 1;
4719 cubic_control[0].y >>= 1;
4721 if(point+1 > outline->contours[contour])
4722 cubic_control[3] = outline->points[first_pt];
4723 else {
4724 cubic_control[3] = outline->points[point+1];
4725 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4726 cubic_control[3].x += outline->points[point].x + 1;
4727 cubic_control[3].y += outline->points[point].y + 1;
4728 cubic_control[3].x >>= 1;
4729 cubic_control[3].y >>= 1;
4732 /* r1 = 1/3 p0 + 2/3 p1
4733 r2 = 1/3 p2 + 2/3 p1 */
4734 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4735 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4736 cubic_control[2] = cubic_control[1];
4737 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4738 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4739 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4740 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4741 if(buf) {
4742 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4743 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4744 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4746 cpfx += 3;
4747 point++;
4749 } while(point <= outline->contours[contour] &&
4750 (outline->tags[point] & FT_Curve_Tag_On) ==
4751 (outline->tags[point-1] & FT_Curve_Tag_On));
4752 /* At the end of a contour Windows adds the start point,
4753 but only for Beziers and we've already done that.
4755 if(point <= outline->contours[contour] &&
4756 outline->tags[point] & FT_Curve_Tag_On) {
4757 /* This is the closing pt of a bezier, but we've already
4758 added it, so just inc point and carry on */
4759 point++;
4761 if(buf) {
4762 ppc->wType = type;
4763 ppc->cpfx = cpfx;
4765 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4767 if(buf)
4768 pph->cb = needed - pph_start;
4770 break;
4773 default:
4774 FIXME("Unsupported format %d\n", format);
4775 LeaveCriticalSection( &freetype_cs );
4776 return GDI_ERROR;
4778 LeaveCriticalSection( &freetype_cs );
4779 return needed;
4782 static BOOL get_bitmap_text_metrics(GdiFont *font)
4784 FT_Face ft_face = font->ft_face;
4785 #ifdef HAVE_FREETYPE_FTWINFNT_H
4786 FT_WinFNT_HeaderRec winfnt_header;
4787 #endif
4788 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4789 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4790 font->potm->otmSize = size;
4792 #define TM font->potm->otmTextMetrics
4793 #ifdef HAVE_FREETYPE_FTWINFNT_H
4794 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4796 TM.tmHeight = winfnt_header.pixel_height;
4797 TM.tmAscent = winfnt_header.ascent;
4798 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4799 TM.tmInternalLeading = winfnt_header.internal_leading;
4800 TM.tmExternalLeading = winfnt_header.external_leading;
4801 TM.tmAveCharWidth = winfnt_header.avg_width;
4802 TM.tmMaxCharWidth = winfnt_header.max_width;
4803 TM.tmWeight = winfnt_header.weight;
4804 TM.tmOverhang = 0;
4805 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4806 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4807 TM.tmFirstChar = winfnt_header.first_char;
4808 TM.tmLastChar = winfnt_header.last_char;
4809 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4810 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4811 TM.tmItalic = winfnt_header.italic;
4812 TM.tmUnderlined = font->underline;
4813 TM.tmStruckOut = font->strikeout;
4814 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4815 TM.tmCharSet = winfnt_header.charset;
4817 else
4818 #endif
4820 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4821 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4822 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4823 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4824 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4825 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4826 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4827 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4828 TM.tmOverhang = 0;
4829 TM.tmDigitizedAspectX = 96; /* FIXME */
4830 TM.tmDigitizedAspectY = 96; /* FIXME */
4831 TM.tmFirstChar = 1;
4832 TM.tmLastChar = 255;
4833 TM.tmDefaultChar = 32;
4834 TM.tmBreakChar = 32;
4835 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4836 TM.tmUnderlined = font->underline;
4837 TM.tmStruckOut = font->strikeout;
4838 /* NB inverted meaning of TMPF_FIXED_PITCH */
4839 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4840 TM.tmCharSet = font->charset;
4842 #undef TM
4844 return TRUE;
4848 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4850 float scale_x;
4852 if (font->aveWidth)
4854 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4855 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4857 else
4858 scale_x = font->scale_y;
4860 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4861 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4862 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4863 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4864 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4866 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4867 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4870 /*************************************************************
4871 * WineEngGetTextMetrics
4874 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4876 EnterCriticalSection( &freetype_cs );
4877 if(!font->potm) {
4878 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4879 if(!get_bitmap_text_metrics(font))
4881 LeaveCriticalSection( &freetype_cs );
4882 return FALSE;
4885 if(!font->potm)
4887 LeaveCriticalSection( &freetype_cs );
4888 return FALSE;
4890 *ptm = font->potm->otmTextMetrics;
4891 scale_font_metrics(font, ptm);
4892 LeaveCriticalSection( &freetype_cs );
4893 return TRUE;
4897 /*************************************************************
4898 * WineEngGetOutlineTextMetrics
4901 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4902 OUTLINETEXTMETRICW *potm)
4904 FT_Face ft_face = font->ft_face;
4905 UINT needed, lenfam, lensty, ret;
4906 TT_OS2 *pOS2;
4907 TT_HoriHeader *pHori;
4908 TT_Postscript *pPost;
4909 FT_Fixed x_scale, y_scale;
4910 WCHAR *family_nameW, *style_nameW;
4911 static const WCHAR spaceW[] = {' ', '\0'};
4912 char *cp;
4913 INT ascent, descent;
4915 TRACE("font=%p\n", font);
4917 if(!FT_IS_SCALABLE(ft_face))
4918 return 0;
4920 EnterCriticalSection( &freetype_cs );
4922 if(font->potm) {
4923 if(cbSize >= font->potm->otmSize)
4925 memcpy(potm, font->potm, font->potm->otmSize);
4926 scale_font_metrics(font, &potm->otmTextMetrics);
4928 LeaveCriticalSection( &freetype_cs );
4929 return font->potm->otmSize;
4933 needed = sizeof(*potm);
4935 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4936 family_nameW = strdupW(font->name);
4938 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4939 * sizeof(WCHAR);
4940 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4941 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4942 style_nameW, lensty/sizeof(WCHAR));
4944 /* These names should be read from the TT name table */
4946 /* length of otmpFamilyName */
4947 needed += lenfam;
4949 /* length of otmpFaceName */
4950 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
4951 needed += lenfam; /* just the family name */
4952 } else {
4953 needed += lenfam + lensty; /* family + " " + style */
4956 /* length of otmpStyleName */
4957 needed += lensty;
4959 /* length of otmpFullName */
4960 needed += lenfam + lensty;
4963 x_scale = ft_face->size->metrics.x_scale;
4964 y_scale = ft_face->size->metrics.y_scale;
4966 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4967 if(!pOS2) {
4968 FIXME("Can't find OS/2 table - not TT font?\n");
4969 ret = 0;
4970 goto end;
4973 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4974 if(!pHori) {
4975 FIXME("Can't find HHEA table - not TT font?\n");
4976 ret = 0;
4977 goto end;
4980 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4982 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",
4983 pOS2->usWinAscent, pOS2->usWinDescent,
4984 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4985 ft_face->ascender, ft_face->descender, ft_face->height,
4986 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4987 ft_face->bbox.yMax, ft_face->bbox.yMin);
4989 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4990 font->potm->otmSize = needed;
4992 #define TM font->potm->otmTextMetrics
4994 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4995 ascent = pHori->Ascender;
4996 descent = -pHori->Descender;
4997 } else {
4998 ascent = pOS2->usWinAscent;
4999 descent = pOS2->usWinDescent;
5002 if(font->yMax) {
5003 TM.tmAscent = font->yMax;
5004 TM.tmDescent = -font->yMin;
5005 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5006 } else {
5007 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5008 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5009 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5010 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5013 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5015 /* MSDN says:
5016 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5018 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5019 ((ascent + descent) -
5020 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5022 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5023 if (TM.tmAveCharWidth == 0) {
5024 TM.tmAveCharWidth = 1;
5026 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5027 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
5028 TM.tmOverhang = 0;
5029 TM.tmDigitizedAspectX = 300;
5030 TM.tmDigitizedAspectY = 300;
5031 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5032 * symbol range to 0 - f0ff
5034 if (font->charset == SYMBOL_CHARSET)
5036 TM.tmFirstChar = 0;
5037 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5039 else
5041 TM.tmFirstChar = pOS2->usFirstCharIndex;
5042 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5044 TM.tmLastChar = pOS2->usLastCharIndex;
5045 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5046 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5047 TM.tmUnderlined = font->underline;
5048 TM.tmStruckOut = font->strikeout;
5050 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5051 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5052 (pOS2->version == 0xFFFFU ||
5053 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5054 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5055 else
5056 TM.tmPitchAndFamily = 0;
5058 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5059 case PAN_FAMILY_SCRIPT:
5060 TM.tmPitchAndFamily |= FF_SCRIPT;
5061 break;
5062 case PAN_FAMILY_DECORATIVE:
5063 case PAN_FAMILY_PICTORIAL:
5064 TM.tmPitchAndFamily |= FF_DECORATIVE;
5065 break;
5066 case PAN_FAMILY_TEXT_DISPLAY:
5067 if(TM.tmPitchAndFamily == 0) /* fixed */
5068 TM.tmPitchAndFamily = FF_MODERN;
5069 else {
5070 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5071 case PAN_SERIF_NORMAL_SANS:
5072 case PAN_SERIF_OBTUSE_SANS:
5073 case PAN_SERIF_PERP_SANS:
5074 TM.tmPitchAndFamily |= FF_SWISS;
5075 break;
5076 default:
5077 TM.tmPitchAndFamily |= FF_ROMAN;
5080 break;
5081 default:
5082 TM.tmPitchAndFamily |= FF_DONTCARE;
5085 if(FT_IS_SCALABLE(ft_face))
5086 TM.tmPitchAndFamily |= TMPF_VECTOR;
5088 if(FT_IS_SFNT(ft_face))
5090 if (font->ntmFlags & NTM_PS_OPENTYPE)
5091 TM.tmPitchAndFamily |= TMPF_DEVICE;
5092 else
5093 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5096 TM.tmCharSet = font->charset;
5097 #undef TM
5099 font->potm->otmFiller = 0;
5100 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5101 font->potm->otmfsSelection = pOS2->fsSelection;
5102 font->potm->otmfsType = pOS2->fsType;
5103 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5104 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5105 font->potm->otmItalicAngle = 0; /* POST table */
5106 font->potm->otmEMSquare = ft_face->units_per_EM;
5107 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5108 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5109 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5110 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5111 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5112 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5113 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5114 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5115 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5116 font->potm->otmMacAscent = 0; /* where do these come from ? */
5117 font->potm->otmMacDescent = 0;
5118 font->potm->otmMacLineGap = 0;
5119 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5120 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5121 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5122 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5123 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5124 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5125 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5126 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5127 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5128 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5129 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5130 if(!pPost) {
5131 font->potm->otmsUnderscoreSize = 0;
5132 font->potm->otmsUnderscorePosition = 0;
5133 } else {
5134 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5135 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5138 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5139 cp = (char*)font->potm + sizeof(*font->potm);
5140 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5141 strcpyW((WCHAR*)cp, family_nameW);
5142 cp += lenfam;
5143 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5144 strcpyW((WCHAR*)cp, style_nameW);
5145 cp += lensty;
5146 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5147 strcpyW((WCHAR*)cp, family_nameW);
5148 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5149 strcatW((WCHAR*)cp, spaceW);
5150 strcatW((WCHAR*)cp, style_nameW);
5151 cp += lenfam + lensty;
5152 } else
5153 cp += lenfam;
5154 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5155 strcpyW((WCHAR*)cp, family_nameW);
5156 strcatW((WCHAR*)cp, spaceW);
5157 strcatW((WCHAR*)cp, style_nameW);
5158 ret = needed;
5160 if(potm && needed <= cbSize)
5162 memcpy(potm, font->potm, font->potm->otmSize);
5163 scale_font_metrics(font, &potm->otmTextMetrics);
5166 end:
5167 HeapFree(GetProcessHeap(), 0, style_nameW);
5168 HeapFree(GetProcessHeap(), 0, family_nameW);
5170 LeaveCriticalSection( &freetype_cs );
5171 return ret;
5174 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5176 HFONTLIST *hfontlist;
5177 child->font = alloc_font();
5178 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5179 if(!child->font->ft_face)
5181 free_font(child->font);
5182 child->font = NULL;
5183 return FALSE;
5186 child->font->ntmFlags = child->face->ntmFlags;
5187 child->font->orientation = font->orientation;
5188 child->font->scale_y = font->scale_y;
5189 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5190 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5191 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5192 child->font->base_font = font;
5193 list_add_head(&child_font_list, &child->font->entry);
5194 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5195 return TRUE;
5198 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5200 FT_UInt g;
5201 CHILD_FONT *child_font;
5203 if(font->base_font)
5204 font = font->base_font;
5206 *linked_font = font;
5208 if((*glyph = get_glyph_index(font, c)))
5209 return TRUE;
5211 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5213 if(!child_font->font)
5214 if(!load_child_font(font, child_font))
5215 continue;
5217 if(!child_font->font->ft_face)
5218 continue;
5219 g = get_glyph_index(child_font->font, c);
5220 if(g)
5222 *glyph = g;
5223 *linked_font = child_font->font;
5224 return TRUE;
5227 return FALSE;
5230 /*************************************************************
5231 * WineEngGetCharWidth
5234 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5235 LPINT buffer)
5237 UINT c;
5238 GLYPHMETRICS gm;
5239 FT_UInt glyph_index;
5240 GdiFont *linked_font;
5242 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5244 EnterCriticalSection( &freetype_cs );
5245 for(c = firstChar; c <= lastChar; c++) {
5246 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5247 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5248 &gm, 0, NULL, NULL);
5249 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5251 LeaveCriticalSection( &freetype_cs );
5252 return TRUE;
5255 /*************************************************************
5256 * WineEngGetCharABCWidths
5259 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5260 LPABC buffer)
5262 UINT c;
5263 GLYPHMETRICS gm;
5264 FT_UInt glyph_index;
5265 GdiFont *linked_font;
5267 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5269 if(!FT_IS_SCALABLE(font->ft_face))
5270 return FALSE;
5272 EnterCriticalSection( &freetype_cs );
5274 for(c = firstChar; c <= lastChar; c++) {
5275 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5276 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5277 &gm, 0, NULL, NULL);
5278 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5279 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5280 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5281 FONT_GM(linked_font,glyph_index)->bbx;
5283 LeaveCriticalSection( &freetype_cs );
5284 return TRUE;
5287 /*************************************************************
5288 * WineEngGetCharABCWidthsI
5291 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5292 LPABC buffer)
5294 UINT c;
5295 GLYPHMETRICS gm;
5296 FT_UInt glyph_index;
5297 GdiFont *linked_font;
5299 if(!FT_HAS_HORIZONTAL(font->ft_face))
5300 return FALSE;
5302 EnterCriticalSection( &freetype_cs );
5304 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5305 if (!pgi)
5306 for(c = firstChar; c < firstChar+count; c++) {
5307 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5308 &gm, 0, NULL, NULL);
5309 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5310 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5311 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5312 - FONT_GM(linked_font,c)->bbx;
5314 else
5315 for(c = 0; c < count; c++) {
5316 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5317 &gm, 0, NULL, NULL);
5318 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5319 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5320 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5321 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5324 LeaveCriticalSection( &freetype_cs );
5325 return TRUE;
5328 /*************************************************************
5329 * WineEngGetTextExtentExPoint
5332 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5333 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5335 INT idx;
5336 INT nfit = 0, ext;
5337 GLYPHMETRICS gm;
5338 TEXTMETRICW tm;
5339 FT_UInt glyph_index;
5340 GdiFont *linked_font;
5342 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5343 max_ext, size);
5345 EnterCriticalSection( &freetype_cs );
5347 size->cx = 0;
5348 WineEngGetTextMetrics(font, &tm);
5349 size->cy = tm.tmHeight;
5351 for(idx = 0; idx < count; idx++) {
5352 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5353 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5354 &gm, 0, NULL, NULL);
5355 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5356 ext = size->cx;
5357 if (! pnfit || ext <= max_ext) {
5358 ++nfit;
5359 if (dxs)
5360 dxs[idx] = ext;
5364 if (pnfit)
5365 *pnfit = nfit;
5367 LeaveCriticalSection( &freetype_cs );
5368 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5369 return TRUE;
5372 /*************************************************************
5373 * WineEngGetTextExtentExPointI
5376 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5377 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5379 INT idx;
5380 INT nfit = 0, ext;
5381 GLYPHMETRICS gm;
5382 TEXTMETRICW tm;
5384 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5386 EnterCriticalSection( &freetype_cs );
5388 size->cx = 0;
5389 WineEngGetTextMetrics(font, &tm);
5390 size->cy = tm.tmHeight;
5392 for(idx = 0; idx < count; idx++) {
5393 WineEngGetGlyphOutline(font, indices[idx],
5394 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5395 NULL);
5396 size->cx += FONT_GM(font,indices[idx])->adv;
5397 ext = size->cx;
5398 if (! pnfit || ext <= max_ext) {
5399 ++nfit;
5400 if (dxs)
5401 dxs[idx] = ext;
5405 if (pnfit)
5406 *pnfit = nfit;
5408 LeaveCriticalSection( &freetype_cs );
5409 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5410 return TRUE;
5413 /*************************************************************
5414 * WineEngGetFontData
5417 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5418 DWORD cbData)
5420 FT_Face ft_face = font->ft_face;
5421 FT_ULong len;
5422 FT_Error err;
5424 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5425 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5426 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5428 if(!FT_IS_SFNT(ft_face))
5429 return GDI_ERROR;
5431 if(!buf || !cbData)
5432 len = 0;
5433 else
5434 len = cbData;
5436 if(table) { /* MS tags differ in endianness from FT ones */
5437 table = table >> 24 | table << 24 |
5438 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5441 /* make sure value of len is the value freetype says it needs */
5442 if(buf && len)
5444 FT_ULong needed = 0;
5445 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5446 if( !err && needed < len) len = needed;
5448 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5450 if(err) {
5451 TRACE("Can't find table %c%c%c%c\n",
5452 /* bytes were reversed */
5453 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5454 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5455 return GDI_ERROR;
5457 return len;
5460 /*************************************************************
5461 * WineEngGetTextFace
5464 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5466 if(str) {
5467 lstrcpynW(str, font->name, count);
5468 return strlenW(font->name);
5469 } else
5470 return strlenW(font->name) + 1;
5473 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5475 if (fs) *fs = font->fs;
5476 return font->charset;
5479 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5481 GdiFont *font = dc->gdiFont, *linked_font;
5482 struct list *first_hfont;
5483 BOOL ret;
5485 EnterCriticalSection( &freetype_cs );
5486 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5487 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5488 if(font == linked_font)
5489 *new_hfont = dc->hFont;
5490 else
5492 first_hfont = list_head(&linked_font->hfontlist);
5493 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5495 LeaveCriticalSection( &freetype_cs );
5496 return ret;
5499 /* Retrieve a list of supported Unicode ranges for a given font.
5500 * Can be called with NULL gs to calculate the buffer size. Returns
5501 * the number of ranges found.
5503 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5505 DWORD num_ranges = 0;
5507 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5509 FT_UInt glyph_code;
5510 FT_ULong char_code, char_code_prev;
5512 glyph_code = 0;
5513 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5515 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5516 face->num_glyphs, glyph_code, char_code);
5518 if (!glyph_code) return 0;
5520 if (gs)
5522 gs->ranges[0].wcLow = (USHORT)char_code;
5523 gs->ranges[0].cGlyphs = 0;
5524 gs->cGlyphsSupported = 0;
5527 num_ranges = 1;
5528 while (glyph_code)
5530 if (char_code < char_code_prev)
5532 ERR("expected increasing char code from FT_Get_Next_Char\n");
5533 return 0;
5535 if (char_code - char_code_prev > 1)
5537 num_ranges++;
5538 if (gs)
5540 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5541 gs->ranges[num_ranges - 1].cGlyphs = 1;
5542 gs->cGlyphsSupported++;
5545 else if (gs)
5547 gs->ranges[num_ranges - 1].cGlyphs++;
5548 gs->cGlyphsSupported++;
5550 char_code_prev = char_code;
5551 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5554 else
5555 FIXME("encoding %u not supported\n", face->charmap->encoding);
5557 return num_ranges;
5560 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5562 DWORD size = 0;
5563 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5565 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5566 if (glyphset)
5568 glyphset->cbThis = size;
5569 glyphset->cRanges = num_ranges;
5571 return size;
5574 /*************************************************************
5575 * FontIsLinked
5577 BOOL WineEngFontIsLinked(GdiFont *font)
5579 BOOL ret;
5580 EnterCriticalSection( &freetype_cs );
5581 ret = !list_empty(&font->child_fonts);
5582 LeaveCriticalSection( &freetype_cs );
5583 return ret;
5586 static BOOL is_hinting_enabled(void)
5588 /* Use the >= 2.2.0 function if available */
5589 if(pFT_Get_TrueType_Engine_Type)
5591 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5592 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5594 #ifdef FT_DRIVER_HAS_HINTER
5595 else
5597 FT_Module mod;
5599 /* otherwise if we've been compiled with < 2.2.0 headers
5600 use the internal macro */
5601 mod = pFT_Get_Module(library, "truetype");
5602 if(mod && FT_DRIVER_HAS_HINTER(mod))
5603 return TRUE;
5605 #endif
5607 return FALSE;
5610 /*************************************************************************
5611 * GetRasterizerCaps (GDI32.@)
5613 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5615 static int hinting = -1;
5617 if(hinting == -1)
5619 hinting = is_hinting_enabled();
5620 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5623 lprs->nSize = sizeof(RASTERIZER_STATUS);
5624 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5625 lprs->nLanguageID = 0;
5626 return TRUE;
5629 /*************************************************************************
5630 * Kerning support for TrueType fonts
5632 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5634 struct TT_kern_table
5636 USHORT version;
5637 USHORT nTables;
5640 struct TT_kern_subtable
5642 USHORT version;
5643 USHORT length;
5644 union
5646 USHORT word;
5647 struct
5649 USHORT horizontal : 1;
5650 USHORT minimum : 1;
5651 USHORT cross_stream: 1;
5652 USHORT override : 1;
5653 USHORT reserved1 : 4;
5654 USHORT format : 8;
5655 } bits;
5656 } coverage;
5659 struct TT_format0_kern_subtable
5661 USHORT nPairs;
5662 USHORT searchRange;
5663 USHORT entrySelector;
5664 USHORT rangeShift;
5667 struct TT_kern_pair
5669 USHORT left;
5670 USHORT right;
5671 short value;
5674 static DWORD parse_format0_kern_subtable(GdiFont *font,
5675 const struct TT_format0_kern_subtable *tt_f0_ks,
5676 const USHORT *glyph_to_char,
5677 KERNINGPAIR *kern_pair, DWORD cPairs)
5679 USHORT i, nPairs;
5680 const struct TT_kern_pair *tt_kern_pair;
5682 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5684 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5686 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5687 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5688 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5690 if (!kern_pair || !cPairs)
5691 return nPairs;
5693 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5695 nPairs = min(nPairs, cPairs);
5697 for (i = 0; i < nPairs; i++)
5699 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5700 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5701 /* this algorithm appears to better match what Windows does */
5702 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5703 if (kern_pair->iKernAmount < 0)
5705 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5706 kern_pair->iKernAmount -= font->ppem;
5708 else if (kern_pair->iKernAmount > 0)
5710 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5711 kern_pair->iKernAmount += font->ppem;
5713 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5715 TRACE("left %u right %u value %d\n",
5716 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5718 kern_pair++;
5720 TRACE("copied %u entries\n", nPairs);
5721 return nPairs;
5724 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5726 DWORD length;
5727 void *buf;
5728 const struct TT_kern_table *tt_kern_table;
5729 const struct TT_kern_subtable *tt_kern_subtable;
5730 USHORT i, nTables;
5731 USHORT *glyph_to_char;
5733 EnterCriticalSection( &freetype_cs );
5734 if (font->total_kern_pairs != (DWORD)-1)
5736 if (cPairs && kern_pair)
5738 cPairs = min(cPairs, font->total_kern_pairs);
5739 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5740 LeaveCriticalSection( &freetype_cs );
5741 return cPairs;
5743 LeaveCriticalSection( &freetype_cs );
5744 return font->total_kern_pairs;
5747 font->total_kern_pairs = 0;
5749 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5751 if (length == GDI_ERROR)
5753 TRACE("no kerning data in the font\n");
5754 LeaveCriticalSection( &freetype_cs );
5755 return 0;
5758 buf = HeapAlloc(GetProcessHeap(), 0, length);
5759 if (!buf)
5761 WARN("Out of memory\n");
5762 LeaveCriticalSection( &freetype_cs );
5763 return 0;
5766 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5768 /* build a glyph index to char code map */
5769 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5770 if (!glyph_to_char)
5772 WARN("Out of memory allocating a glyph index to char code map\n");
5773 HeapFree(GetProcessHeap(), 0, buf);
5774 LeaveCriticalSection( &freetype_cs );
5775 return 0;
5778 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5780 FT_UInt glyph_code;
5781 FT_ULong char_code;
5783 glyph_code = 0;
5784 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5786 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5787 font->ft_face->num_glyphs, glyph_code, char_code);
5789 while (glyph_code)
5791 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5793 /* FIXME: This doesn't match what Windows does: it does some fancy
5794 * things with duplicate glyph index to char code mappings, while
5795 * we just avoid overriding existing entries.
5797 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5798 glyph_to_char[glyph_code] = (USHORT)char_code;
5800 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5803 else
5805 ULONG n;
5807 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5808 for (n = 0; n <= 65535; n++)
5809 glyph_to_char[n] = (USHORT)n;
5812 tt_kern_table = buf;
5813 nTables = GET_BE_WORD(tt_kern_table->nTables);
5814 TRACE("version %u, nTables %u\n",
5815 GET_BE_WORD(tt_kern_table->version), nTables);
5817 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5819 for (i = 0; i < nTables; i++)
5821 struct TT_kern_subtable tt_kern_subtable_copy;
5823 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5824 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5825 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5827 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5828 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5829 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5831 /* According to the TrueType specification this is the only format
5832 * that will be properly interpreted by Windows and OS/2
5834 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5836 DWORD new_chunk, old_total = font->total_kern_pairs;
5838 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5839 glyph_to_char, NULL, 0);
5840 font->total_kern_pairs += new_chunk;
5842 if (!font->kern_pairs)
5843 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5844 font->total_kern_pairs * sizeof(*font->kern_pairs));
5845 else
5846 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5847 font->total_kern_pairs * sizeof(*font->kern_pairs));
5849 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5850 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5852 else
5853 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5855 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5858 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5859 HeapFree(GetProcessHeap(), 0, buf);
5861 if (cPairs && kern_pair)
5863 cPairs = min(cPairs, font->total_kern_pairs);
5864 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5865 LeaveCriticalSection( &freetype_cs );
5866 return cPairs;
5868 LeaveCriticalSection( &freetype_cs );
5869 return font->total_kern_pairs;
5872 #else /* HAVE_FREETYPE */
5874 /*************************************************************************/
5876 BOOL WineEngInit(void)
5878 return FALSE;
5880 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5882 return NULL;
5884 BOOL WineEngDestroyFontInstance(HFONT hfont)
5886 return FALSE;
5889 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5891 return 1;
5894 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5895 LPWORD pgi, DWORD flags)
5897 return GDI_ERROR;
5900 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5901 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5902 const MAT2* lpmat)
5904 ERR("called but we don't have FreeType\n");
5905 return GDI_ERROR;
5908 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5910 ERR("called but we don't have FreeType\n");
5911 return FALSE;
5914 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5915 OUTLINETEXTMETRICW *potm)
5917 ERR("called but we don't have FreeType\n");
5918 return 0;
5921 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5922 LPINT buffer)
5924 ERR("called but we don't have FreeType\n");
5925 return FALSE;
5928 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5929 LPABC buffer)
5931 ERR("called but we don't have FreeType\n");
5932 return FALSE;
5935 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5936 LPABC buffer)
5938 ERR("called but we don't have FreeType\n");
5939 return FALSE;
5942 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5943 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5945 ERR("called but we don't have FreeType\n");
5946 return FALSE;
5949 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5950 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5952 ERR("called but we don't have FreeType\n");
5953 return FALSE;
5956 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5957 DWORD cbData)
5959 ERR("called but we don't have FreeType\n");
5960 return GDI_ERROR;
5963 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5965 ERR("called but we don't have FreeType\n");
5966 return 0;
5969 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5971 FIXME(":stub\n");
5972 return 1;
5975 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5977 FIXME(":stub\n");
5978 return TRUE;
5981 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5983 FIXME(":stub\n");
5984 return NULL;
5987 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5989 FIXME(":stub\n");
5990 return DEFAULT_CHARSET;
5993 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5995 return FALSE;
5998 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6000 FIXME("(%p, %p): stub\n", font, glyphset);
6001 return 0;
6004 BOOL WineEngFontIsLinked(GdiFont *font)
6006 return FALSE;
6009 /*************************************************************************
6010 * GetRasterizerCaps (GDI32.@)
6012 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6014 lprs->nSize = sizeof(RASTERIZER_STATUS);
6015 lprs->wFlags = 0;
6016 lprs->nLanguageID = 0;
6017 return TRUE;
6020 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6022 ERR("called but we don't have FreeType\n");
6023 return 0;
6026 #endif /* HAVE_FREETYPE */