push 7f8c39dca3a5819e8ef115eebf7abed537de3a22
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob731b1c5870627366524e3283b5f651d7bdf3811e
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 double 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(double 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 = MulDiv(ft_face->units_per_EM, height,
2685 pHori->Ascender - pHori->Descender);
2686 else
2687 ppem = MulDiv(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);
2788 TRACE("height %d => ppem %d\n", height, font->ppem);
2790 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2791 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2792 } else {
2793 font->ppem = height;
2794 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2795 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2797 return ft_face;
2801 static int get_nearest_charset(Face *face, int *cp)
2803 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2804 a single face with the requested charset. The idea is to check if
2805 the selected font supports the current ANSI codepage, if it does
2806 return the corresponding charset, else return the first charset */
2808 CHARSETINFO csi;
2809 int acp = GetACP(), i;
2810 DWORD fs0;
2812 *cp = acp;
2813 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2814 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2815 return csi.ciCharset;
2817 for(i = 0; i < 32; i++) {
2818 fs0 = 1L << i;
2819 if(face->fs.fsCsb[0] & fs0) {
2820 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2821 *cp = csi.ciACP;
2822 return csi.ciCharset;
2824 else
2825 FIXME("TCI failing on %x\n", fs0);
2829 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2830 face->fs.fsCsb[0], face->file);
2831 *cp = acp;
2832 return DEFAULT_CHARSET;
2835 static GdiFont *alloc_font(void)
2837 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2838 ret->gmsize = 1;
2839 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2840 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2841 ret->potm = NULL;
2842 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2843 ret->total_kern_pairs = (DWORD)-1;
2844 ret->kern_pairs = NULL;
2845 list_init(&ret->hfontlist);
2846 list_init(&ret->child_fonts);
2847 return ret;
2850 static void free_font(GdiFont *font)
2852 struct list *cursor, *cursor2;
2853 int i;
2855 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2857 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2858 struct list *first_hfont;
2859 HFONTLIST *hfontlist;
2860 list_remove(cursor);
2861 if(child->font)
2863 first_hfont = list_head(&child->font->hfontlist);
2864 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2865 DeleteObject(hfontlist->hfont);
2866 HeapFree(GetProcessHeap(), 0, hfontlist);
2867 free_font(child->font);
2869 HeapFree(GetProcessHeap(), 0, child);
2872 if (font->ft_face) pFT_Done_Face(font->ft_face);
2873 if (font->mapping) unmap_font_file( font->mapping );
2874 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2875 HeapFree(GetProcessHeap(), 0, font->potm);
2876 HeapFree(GetProcessHeap(), 0, font->name);
2877 for (i = 0; i < font->gmsize; i++)
2878 HeapFree(GetProcessHeap(),0,font->gm[i]);
2879 HeapFree(GetProcessHeap(), 0, font->gm);
2880 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2881 HeapFree(GetProcessHeap(), 0, font);
2885 /*************************************************************
2886 * load_VDMX
2888 * load the vdmx entry for the specified height
2891 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2892 ( ( (FT_ULong)_x4 << 24 ) | \
2893 ( (FT_ULong)_x3 << 16 ) | \
2894 ( (FT_ULong)_x2 << 8 ) | \
2895 (FT_ULong)_x1 )
2897 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2899 typedef struct {
2900 BYTE bCharSet;
2901 BYTE xRatio;
2902 BYTE yStartRatio;
2903 BYTE yEndRatio;
2904 } Ratios;
2906 typedef struct {
2907 WORD recs;
2908 BYTE startsz;
2909 BYTE endsz;
2910 } VDMX_group;
2912 static LONG load_VDMX(GdiFont *font, LONG height)
2914 WORD hdr[3], tmp;
2915 VDMX_group group;
2916 BYTE devXRatio, devYRatio;
2917 USHORT numRecs, numRatios;
2918 DWORD result, offset = -1;
2919 LONG ppem = 0;
2920 int i;
2922 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2924 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2925 return ppem;
2927 /* FIXME: need the real device aspect ratio */
2928 devXRatio = 1;
2929 devYRatio = 1;
2931 numRecs = GET_BE_WORD(hdr[1]);
2932 numRatios = GET_BE_WORD(hdr[2]);
2934 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2935 for(i = 0; i < numRatios; i++) {
2936 Ratios ratio;
2938 offset = (3 * 2) + (i * sizeof(Ratios));
2939 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2940 offset = -1;
2942 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2944 if((ratio.xRatio == 0 &&
2945 ratio.yStartRatio == 0 &&
2946 ratio.yEndRatio == 0) ||
2947 (devXRatio == ratio.xRatio &&
2948 devYRatio >= ratio.yStartRatio &&
2949 devYRatio <= ratio.yEndRatio))
2951 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2952 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2953 offset = GET_BE_WORD(tmp);
2954 break;
2958 if(offset == -1) {
2959 FIXME("No suitable ratio found\n");
2960 return ppem;
2963 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2964 USHORT recs;
2965 BYTE startsz, endsz;
2966 WORD *vTable;
2968 recs = GET_BE_WORD(group.recs);
2969 startsz = group.startsz;
2970 endsz = group.endsz;
2972 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2974 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2975 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2976 if(result == GDI_ERROR) {
2977 FIXME("Failed to retrieve vTable\n");
2978 goto end;
2981 if(height > 0) {
2982 for(i = 0; i < recs; i++) {
2983 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2984 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2985 ppem = GET_BE_WORD(vTable[i * 3]);
2987 if(yMax + -yMin == height) {
2988 font->yMax = yMax;
2989 font->yMin = yMin;
2990 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2991 break;
2993 if(yMax + -yMin > height) {
2994 if(--i < 0) {
2995 ppem = 0;
2996 goto end; /* failed */
2998 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2999 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3000 ppem = GET_BE_WORD(vTable[i * 3]);
3001 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3002 break;
3005 if(!font->yMax) {
3006 ppem = 0;
3007 TRACE("ppem not found for height %d\n", height);
3009 } else {
3010 ppem = -height;
3011 if(ppem < startsz || ppem > endsz)
3012 goto end;
3014 for(i = 0; i < recs; i++) {
3015 USHORT yPelHeight;
3016 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3018 if(yPelHeight > ppem)
3019 break; /* failed */
3021 if(yPelHeight == ppem) {
3022 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3023 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3024 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3025 break;
3029 end:
3030 HeapFree(GetProcessHeap(), 0, vTable);
3033 return ppem;
3036 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3038 if(font->font_desc.hash != fd->hash) return TRUE;
3039 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3040 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3041 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3042 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3045 static void calc_hash(FONT_DESC *pfd)
3047 DWORD hash = 0, *ptr, two_chars;
3048 WORD *pwc;
3049 unsigned int i;
3051 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3052 hash ^= *ptr;
3053 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3054 hash ^= *ptr;
3055 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3056 two_chars = *ptr;
3057 pwc = (WCHAR *)&two_chars;
3058 if(!*pwc) break;
3059 *pwc = toupperW(*pwc);
3060 pwc++;
3061 *pwc = toupperW(*pwc);
3062 hash ^= two_chars;
3063 if(!*pwc) break;
3065 hash ^= !pfd->can_use_bitmap;
3066 pfd->hash = hash;
3067 return;
3070 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
3072 GdiFont *ret;
3073 FONT_DESC fd;
3074 HFONTLIST *hflist;
3075 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3077 fd.lf = *plf;
3078 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
3079 fd.can_use_bitmap = can_use_bitmap;
3080 calc_hash(&fd);
3082 /* try the in-use list */
3083 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3084 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3085 if(!fontcmp(ret, &fd)) {
3086 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3087 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3088 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3089 if(hflist->hfont == hfont)
3090 return ret;
3092 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3093 hflist->hfont = hfont;
3094 list_add_head(&ret->hfontlist, &hflist->entry);
3095 return ret;
3099 /* then the unused list */
3100 font_elem_ptr = list_head(&unused_gdi_font_list);
3101 while(font_elem_ptr) {
3102 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3103 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3104 if(!fontcmp(ret, &fd)) {
3105 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3106 assert(list_empty(&ret->hfontlist));
3107 TRACE("Found %p in unused list\n", ret);
3108 list_remove(&ret->entry);
3109 list_add_head(&gdi_font_list, &ret->entry);
3110 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3111 hflist->hfont = hfont;
3112 list_add_head(&ret->hfontlist, &hflist->entry);
3113 return ret;
3116 return NULL;
3120 /*************************************************************
3121 * create_child_font_list
3123 static BOOL create_child_font_list(GdiFont *font)
3125 BOOL ret = FALSE;
3126 SYSTEM_LINKS *font_link;
3127 CHILD_FONT *font_link_entry, *new_child;
3129 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3131 if(!strcmpW(font_link->font_name, font->name))
3133 TRACE("found entry in system list\n");
3134 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3136 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3137 new_child->face = font_link_entry->face;
3138 new_child->font = NULL;
3139 list_add_tail(&font->child_fonts, &new_child->entry);
3140 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3142 ret = TRUE;
3143 break;
3147 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3148 * Sans Serif. This is how asian windows get default fallbacks for fonts
3150 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3151 font->charset != OEM_CHARSET &&
3152 strcmpW(font->name,szDefaultFallbackLink) != 0)
3153 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3155 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3157 TRACE("found entry in default fallback list\n");
3158 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3160 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3161 new_child->face = font_link_entry->face;
3162 new_child->font = NULL;
3163 list_add_tail(&font->child_fonts, &new_child->entry);
3164 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3166 ret = TRUE;
3167 break;
3171 return ret;
3174 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3176 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3178 if (pFT_Set_Charmap)
3180 FT_Int i;
3181 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3183 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3185 for (i = 0; i < ft_face->num_charmaps; i++)
3187 if (ft_face->charmaps[i]->encoding == encoding)
3189 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3190 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3192 switch (ft_face->charmaps[i]->platform_id)
3194 default:
3195 cmap_def = ft_face->charmaps[i];
3196 break;
3197 case 0: /* Apple Unicode */
3198 cmap0 = ft_face->charmaps[i];
3199 break;
3200 case 1: /* Macintosh */
3201 cmap1 = ft_face->charmaps[i];
3202 break;
3203 case 2: /* ISO */
3204 cmap2 = ft_face->charmaps[i];
3205 break;
3206 case 3: /* Microsoft */
3207 cmap3 = ft_face->charmaps[i];
3208 break;
3212 if (cmap3) /* prefer Microsoft cmap table */
3213 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3214 else if (cmap1)
3215 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3216 else if (cmap2)
3217 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3218 else if (cmap0)
3219 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3220 else if (cmap_def)
3221 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3223 return ft_err == FT_Err_Ok;
3226 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3229 /*************************************************************
3230 * WineEngCreateFontInstance
3233 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3235 GdiFont *ret;
3236 Face *face, *best, *best_bitmap;
3237 Family *family, *last_resort_family;
3238 struct list *family_elem_ptr, *face_elem_ptr;
3239 INT height, width = 0;
3240 unsigned int score = 0, new_score;
3241 signed int diff = 0, newdiff;
3242 BOOL bd, it, can_use_bitmap;
3243 LOGFONTW lf;
3244 CHARSETINFO csi;
3245 HFONTLIST *hflist;
3246 FontSubst *psub = NULL;
3248 EnterCriticalSection( &freetype_cs );
3250 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3252 struct list *first_hfont = list_head(&ret->hfontlist);
3253 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3254 if(hflist->hfont == hfont)
3256 LeaveCriticalSection( &freetype_cs );
3257 return ret;
3261 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3263 LeaveCriticalSection( &freetype_cs );
3264 return NULL;
3266 lf.lfWidth = abs(lf.lfWidth);
3268 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3270 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3271 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3272 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3273 lf.lfEscapement);
3275 TRACE("DC transform %f %f %f %f %f %f\n",
3276 dc->xformWorld2Vport.eM11, dc->xformWorld2Vport.eM12,
3277 dc->xformWorld2Vport.eM21, dc->xformWorld2Vport.eM22,
3278 dc->xformWorld2Vport.eDx, dc->xformWorld2Vport.eDy);
3280 /* check the cache first */
3281 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3282 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3283 LeaveCriticalSection( &freetype_cs );
3284 return ret;
3287 TRACE("not in cache\n");
3288 if(list_empty(&font_list)) /* No fonts installed */
3290 TRACE("No fonts installed\n");
3291 LeaveCriticalSection( &freetype_cs );
3292 return NULL;
3294 if(!have_installed_roman_font)
3296 TRACE("No roman font installed\n");
3297 LeaveCriticalSection( &freetype_cs );
3298 return NULL;
3301 ret = alloc_font();
3303 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3304 ret->font_desc.lf = lf;
3305 ret->font_desc.can_use_bitmap = can_use_bitmap;
3306 calc_hash(&ret->font_desc);
3307 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3308 hflist->hfont = hfont;
3309 list_add_head(&ret->hfontlist, &hflist->entry);
3311 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3312 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3313 original value lfCharSet. Note this is a special case for
3314 Symbol and doesn't happen at least for "Wingdings*" */
3316 if(!strcmpiW(lf.lfFaceName, SymbolW))
3317 lf.lfCharSet = SYMBOL_CHARSET;
3319 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3320 switch(lf.lfCharSet) {
3321 case DEFAULT_CHARSET:
3322 csi.fs.fsCsb[0] = 0;
3323 break;
3324 default:
3325 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3326 csi.fs.fsCsb[0] = 0;
3327 break;
3331 family = NULL;
3332 if(lf.lfFaceName[0] != '\0') {
3333 SYSTEM_LINKS *font_link;
3334 CHILD_FONT *font_link_entry;
3335 LPWSTR FaceName = lf.lfFaceName;
3338 * Check for a leading '@' this signals that the font is being
3339 * requested in tategaki mode (vertical writing substitution) but
3340 * does not affect the fontface that is to be selected.
3342 if (lf.lfFaceName[0]=='@')
3343 FaceName = &lf.lfFaceName[1];
3345 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3347 if(psub) {
3348 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3349 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3350 if (psub->to.charset != -1)
3351 lf.lfCharSet = psub->to.charset;
3354 /* We want a match on name and charset or just name if
3355 charset was DEFAULT_CHARSET. If the latter then
3356 we fixup the returned charset later in get_nearest_charset
3357 where we'll either use the charset of the current ansi codepage
3358 or if that's unavailable the first charset that the font supports.
3360 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3361 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3362 if (!strcmpiW(family->FamilyName, FaceName) ||
3363 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3365 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3366 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3367 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3368 if(face->scalable || can_use_bitmap)
3369 goto found;
3375 * Try check the SystemLink list first for a replacement font.
3376 * We may find good replacements there.
3378 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3380 if(!strcmpiW(font_link->font_name, FaceName))
3382 TRACE("found entry in system list\n");
3383 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3385 face = font_link_entry->face;
3386 family = face->family;
3387 if(csi.fs.fsCsb[0] &
3388 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3390 if(face->scalable || can_use_bitmap)
3391 goto found;
3398 psub = NULL; /* substitution is no more relevant */
3400 /* If requested charset was DEFAULT_CHARSET then try using charset
3401 corresponding to the current ansi codepage */
3402 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3404 INT acp = GetACP();
3405 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3406 FIXME("TCI failed on codepage %d\n", acp);
3407 csi.fs.fsCsb[0] = 0;
3408 } else
3409 lf.lfCharSet = csi.ciCharset;
3412 /* Face families are in the top 4 bits of lfPitchAndFamily,
3413 so mask with 0xF0 before testing */
3415 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3416 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3417 strcpyW(lf.lfFaceName, defFixed);
3418 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3419 strcpyW(lf.lfFaceName, defSerif);
3420 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3421 strcpyW(lf.lfFaceName, defSans);
3422 else
3423 strcpyW(lf.lfFaceName, defSans);
3424 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3425 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3426 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3427 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3428 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3429 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3430 if(face->scalable || can_use_bitmap)
3431 goto found;
3436 last_resort_family = NULL;
3437 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3438 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3439 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3440 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3441 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3442 if(face->scalable)
3443 goto found;
3444 if(can_use_bitmap && !last_resort_family)
3445 last_resort_family = family;
3450 if(last_resort_family) {
3451 family = last_resort_family;
3452 csi.fs.fsCsb[0] = 0;
3453 goto found;
3456 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3457 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3458 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3459 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3460 if(face->scalable) {
3461 csi.fs.fsCsb[0] = 0;
3462 WARN("just using first face for now\n");
3463 goto found;
3465 if(can_use_bitmap && !last_resort_family)
3466 last_resort_family = family;
3469 if(!last_resort_family) {
3470 FIXME("can't find a single appropriate font - bailing\n");
3471 free_font(ret);
3472 LeaveCriticalSection( &freetype_cs );
3473 return NULL;
3476 WARN("could only find a bitmap font - this will probably look awful!\n");
3477 family = last_resort_family;
3478 csi.fs.fsCsb[0] = 0;
3480 found:
3481 it = lf.lfItalic ? 1 : 0;
3482 bd = lf.lfWeight > 550 ? 1 : 0;
3484 height = lf.lfHeight;
3486 face = best = best_bitmap = NULL;
3487 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3489 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3491 BOOL italic, bold;
3493 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3494 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3495 new_score = (italic ^ it) + (bold ^ bd);
3496 if(!best || new_score <= score)
3498 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3499 italic, bold, it, bd);
3500 score = new_score;
3501 best = face;
3502 if(best->scalable && score == 0) break;
3503 if(!best->scalable)
3505 if(height > 0)
3506 newdiff = height - (signed int)(best->size.height);
3507 else
3508 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3509 if(!best_bitmap || new_score < score ||
3510 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3512 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3513 diff = newdiff;
3514 best_bitmap = best;
3515 if(score == 0 && diff == 0) break;
3521 if(best)
3522 face = best->scalable ? best : best_bitmap;
3523 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3524 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3526 ret->fs = face->fs;
3528 if(csi.fs.fsCsb[0]) {
3529 ret->charset = lf.lfCharSet;
3530 ret->codepage = csi.ciACP;
3532 else
3533 ret->charset = get_nearest_charset(face, &ret->codepage);
3535 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3536 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3538 ret->aveWidth = height ? lf.lfWidth : 0;
3540 if(!face->scalable) {
3541 /* Windows uses integer scaling factors for bitmap fonts */
3542 INT scale, scaled_height;
3544 if (height != 0) height = diff;
3545 height += face->size.height;
3547 scale = (height + face->size.height - 1) / face->size.height;
3548 scaled_height = scale * face->size.height;
3549 /* XP allows not more than 10% deviation */
3550 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3551 ret->scale_y = scale;
3553 width = face->size.x_ppem >> 6;
3554 height = face->size.y_ppem >> 6;
3556 else
3557 ret->scale_y = 1.0;
3558 TRACE("font scale y: %f\n", ret->scale_y);
3560 ret->ft_face = OpenFontFace(ret, face, width, height);
3562 if (!ret->ft_face)
3564 free_font( ret );
3565 LeaveCriticalSection( &freetype_cs );
3566 return 0;
3569 ret->ntmFlags = face->ntmFlags;
3571 if (ret->charset == SYMBOL_CHARSET &&
3572 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3573 /* No ops */
3575 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3576 /* No ops */
3578 else {
3579 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3582 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3583 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3584 ret->underline = lf.lfUnderline ? 0xff : 0;
3585 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3586 create_child_font_list(ret);
3588 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3590 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3591 if (length != GDI_ERROR)
3593 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3594 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3595 TRACE("Loaded GSUB table of %i bytes\n",length);
3599 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3601 list_add_head(&gdi_font_list, &ret->entry);
3602 LeaveCriticalSection( &freetype_cs );
3603 return ret;
3606 static void dump_gdi_font_list(void)
3608 GdiFont *gdiFont;
3609 struct list *elem_ptr;
3611 TRACE("---------- gdiFont Cache ----------\n");
3612 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3613 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3614 TRACE("gdiFont=%p %s %d\n",
3615 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3618 TRACE("---------- Unused gdiFont Cache ----------\n");
3619 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3620 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3621 TRACE("gdiFont=%p %s %d\n",
3622 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3626 /*************************************************************
3627 * WineEngDestroyFontInstance
3629 * free the gdiFont associated with this handle
3632 BOOL WineEngDestroyFontInstance(HFONT handle)
3634 GdiFont *gdiFont;
3635 HFONTLIST *hflist;
3636 BOOL ret = FALSE;
3637 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3638 int i = 0;
3640 EnterCriticalSection( &freetype_cs );
3642 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3644 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3645 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3646 if(hflist->hfont == handle)
3648 TRACE("removing child font %p from child list\n", gdiFont);
3649 list_remove(&gdiFont->entry);
3650 LeaveCriticalSection( &freetype_cs );
3651 return TRUE;
3655 TRACE("destroying hfont=%p\n", handle);
3656 if(TRACE_ON(font))
3657 dump_gdi_font_list();
3659 font_elem_ptr = list_head(&gdi_font_list);
3660 while(font_elem_ptr) {
3661 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3662 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3664 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3665 while(hfontlist_elem_ptr) {
3666 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3667 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3668 if(hflist->hfont == handle) {
3669 list_remove(&hflist->entry);
3670 HeapFree(GetProcessHeap(), 0, hflist);
3671 ret = TRUE;
3674 if(list_empty(&gdiFont->hfontlist)) {
3675 TRACE("Moving to Unused list\n");
3676 list_remove(&gdiFont->entry);
3677 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3682 font_elem_ptr = list_head(&unused_gdi_font_list);
3683 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3684 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3685 while(font_elem_ptr) {
3686 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3687 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3688 TRACE("freeing %p\n", gdiFont);
3689 list_remove(&gdiFont->entry);
3690 free_font(gdiFont);
3692 LeaveCriticalSection( &freetype_cs );
3693 return ret;
3696 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3697 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3699 GdiFont *font;
3700 LONG width, height;
3702 if (face->cached_enum_data)
3704 TRACE("Cached\n");
3705 *pelf = face->cached_enum_data->elf;
3706 *pntm = face->cached_enum_data->ntm;
3707 *ptype = face->cached_enum_data->type;
3708 return;
3711 font = alloc_font();
3713 if(face->scalable) {
3714 height = -2048; /* 2048 is the most common em size */
3715 width = 0;
3716 } else {
3717 height = face->size.y_ppem >> 6;
3718 width = face->size.x_ppem >> 6;
3720 font->scale_y = 1.0;
3722 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3724 free_font(font);
3725 return;
3728 font->name = strdupW(face->family->FamilyName);
3729 font->ntmFlags = face->ntmFlags;
3731 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3733 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3735 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3737 lstrcpynW(pelf->elfLogFont.lfFaceName,
3738 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3739 LF_FACESIZE);
3740 lstrcpynW(pelf->elfFullName,
3741 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3742 LF_FULLFACESIZE);
3743 lstrcpynW(pelf->elfStyle,
3744 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3745 LF_FACESIZE);
3747 else
3749 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3751 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3753 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3754 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3755 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3758 pntm->ntmTm.ntmFlags = face->ntmFlags;
3759 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3760 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3761 pntm->ntmFontSig = face->fs;
3763 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3765 pelf->elfLogFont.lfEscapement = 0;
3766 pelf->elfLogFont.lfOrientation = 0;
3767 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3768 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3769 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3770 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3771 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3772 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3773 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3774 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3775 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3776 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3777 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3779 *ptype = 0;
3780 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3781 *ptype |= TRUETYPE_FONTTYPE;
3782 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3783 *ptype |= DEVICE_FONTTYPE;
3784 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3785 *ptype |= RASTER_FONTTYPE;
3787 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3788 if (face->cached_enum_data)
3790 face->cached_enum_data->elf = *pelf;
3791 face->cached_enum_data->ntm = *pntm;
3792 face->cached_enum_data->type = *ptype;
3795 free_font(font);
3798 /*************************************************************
3799 * WineEngEnumFonts
3802 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3804 Family *family;
3805 Face *face;
3806 struct list *family_elem_ptr, *face_elem_ptr;
3807 ENUMLOGFONTEXW elf;
3808 NEWTEXTMETRICEXW ntm;
3809 DWORD type;
3810 FONTSIGNATURE fs;
3811 CHARSETINFO csi;
3812 LOGFONTW lf;
3813 int i;
3815 if (!plf)
3817 lf.lfCharSet = DEFAULT_CHARSET;
3818 lf.lfPitchAndFamily = 0;
3819 lf.lfFaceName[0] = 0;
3820 plf = &lf;
3823 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3825 EnterCriticalSection( &freetype_cs );
3826 if(plf->lfFaceName[0]) {
3827 FontSubst *psub;
3828 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3830 if(psub) {
3831 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3832 debugstr_w(psub->to.name));
3833 lf = *plf;
3834 strcpyW(lf.lfFaceName, psub->to.name);
3835 plf = &lf;
3838 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3839 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3840 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3841 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3842 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3843 GetEnumStructs(face, &elf, &ntm, &type);
3844 for(i = 0; i < 32; i++) {
3845 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3846 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3847 strcpyW(elf.elfScript, OEM_DOSW);
3848 i = 32; /* break out of loop */
3849 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3850 continue;
3851 else {
3852 fs.fsCsb[0] = 1L << i;
3853 fs.fsCsb[1] = 0;
3854 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3855 TCI_SRCFONTSIG))
3856 csi.ciCharset = DEFAULT_CHARSET;
3857 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3858 if(csi.ciCharset != DEFAULT_CHARSET) {
3859 elf.elfLogFont.lfCharSet =
3860 ntm.ntmTm.tmCharSet = csi.ciCharset;
3861 if(ElfScriptsW[i])
3862 strcpyW(elf.elfScript, ElfScriptsW[i]);
3863 else
3864 FIXME("Unknown elfscript for bit %d\n", i);
3867 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3868 debugstr_w(elf.elfLogFont.lfFaceName),
3869 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3870 csi.ciCharset, type, debugstr_w(elf.elfScript),
3871 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3872 ntm.ntmTm.ntmFlags);
3873 /* release section before callback (FIXME) */
3874 LeaveCriticalSection( &freetype_cs );
3875 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3876 EnterCriticalSection( &freetype_cs );
3881 } else {
3882 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3883 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3884 face_elem_ptr = list_head(&family->faces);
3885 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3886 GetEnumStructs(face, &elf, &ntm, &type);
3887 for(i = 0; i < 32; i++) {
3888 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3889 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3890 strcpyW(elf.elfScript, OEM_DOSW);
3891 i = 32; /* break out of loop */
3892 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3893 continue;
3894 else {
3895 fs.fsCsb[0] = 1L << i;
3896 fs.fsCsb[1] = 0;
3897 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3898 TCI_SRCFONTSIG))
3899 csi.ciCharset = DEFAULT_CHARSET;
3900 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3901 if(csi.ciCharset != DEFAULT_CHARSET) {
3902 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3903 csi.ciCharset;
3904 if(ElfScriptsW[i])
3905 strcpyW(elf.elfScript, ElfScriptsW[i]);
3906 else
3907 FIXME("Unknown elfscript for bit %d\n", i);
3910 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3911 debugstr_w(elf.elfLogFont.lfFaceName),
3912 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3913 csi.ciCharset, type, debugstr_w(elf.elfScript),
3914 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3915 ntm.ntmTm.ntmFlags);
3916 /* release section before callback (FIXME) */
3917 LeaveCriticalSection( &freetype_cs );
3918 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3919 EnterCriticalSection( &freetype_cs );
3923 LeaveCriticalSection( &freetype_cs );
3924 return 1;
3927 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3929 pt->x.value = vec->x >> 6;
3930 pt->x.fract = (vec->x & 0x3f) << 10;
3931 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3932 pt->y.value = vec->y >> 6;
3933 pt->y.fract = (vec->y & 0x3f) << 10;
3934 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3935 return;
3938 /***************************************************
3939 * According to the MSDN documentation on WideCharToMultiByte,
3940 * certain codepages cannot set the default_used parameter.
3941 * This returns TRUE if the codepage can set that parameter, false else
3942 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3944 static BOOL codepage_sets_default_used(UINT codepage)
3946 switch (codepage)
3948 case CP_UTF7:
3949 case CP_UTF8:
3950 case CP_SYMBOL:
3951 return FALSE;
3952 default:
3953 return TRUE;
3958 * GSUB Table handling functions
3961 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3963 const GSUB_CoverageFormat1* cf1;
3965 cf1 = (GSUB_CoverageFormat1*)table;
3967 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3969 int count = GET_BE_WORD(cf1->GlyphCount);
3970 int i;
3971 TRACE("Coverage Format 1, %i glyphs\n",count);
3972 for (i = 0; i < count; i++)
3973 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3974 return i;
3975 return -1;
3977 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3979 const GSUB_CoverageFormat2* cf2;
3980 int i;
3981 int count;
3982 cf2 = (GSUB_CoverageFormat2*)cf1;
3984 count = GET_BE_WORD(cf2->RangeCount);
3985 TRACE("Coverage Format 2, %i ranges\n",count);
3986 for (i = 0; i < count; i++)
3988 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3989 return -1;
3990 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3991 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3993 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3994 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3997 return -1;
3999 else
4000 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4002 return -1;
4005 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4007 const GSUB_ScriptList *script;
4008 const GSUB_Script *deflt = NULL;
4009 int i;
4010 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4012 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4013 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4015 const GSUB_Script *scr;
4016 int offset;
4018 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4019 scr = (GSUB_Script*)((LPBYTE)script + offset);
4021 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4022 return scr;
4023 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4024 deflt = scr;
4026 return deflt;
4029 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4031 int i;
4032 int offset;
4033 const GSUB_LangSys *Lang;
4035 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4037 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4039 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4040 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4042 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4043 return Lang;
4045 offset = GET_BE_WORD(script->DefaultLangSys);
4046 if (offset)
4048 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4049 return Lang;
4051 return NULL;
4054 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4056 int i;
4057 const GSUB_FeatureList *feature;
4058 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4060 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4061 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4063 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4064 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4066 const GSUB_Feature *feat;
4067 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4068 return feat;
4071 return NULL;
4074 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4076 int i;
4077 int offset;
4078 const GSUB_LookupList *lookup;
4079 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4081 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4082 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4084 const GSUB_LookupTable *look;
4085 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4086 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4087 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4088 if (GET_BE_WORD(look->LookupType) != 1)
4089 FIXME("We only handle SubType 1\n");
4090 else
4092 int j;
4094 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4096 const GSUB_SingleSubstFormat1 *ssf1;
4097 offset = GET_BE_WORD(look->SubTable[j]);
4098 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4099 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4101 int offset = GET_BE_WORD(ssf1->Coverage);
4102 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4103 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4105 TRACE(" Glyph 0x%x ->",glyph);
4106 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4107 TRACE(" 0x%x\n",glyph);
4110 else
4112 const GSUB_SingleSubstFormat2 *ssf2;
4113 INT index;
4114 INT offset;
4116 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4117 offset = GET_BE_WORD(ssf1->Coverage);
4118 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4119 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4120 TRACE(" Coverage index %i\n",index);
4121 if (index != -1)
4123 TRACE(" Glyph is 0x%x ->",glyph);
4124 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4125 TRACE("0x%x\n",glyph);
4131 return glyph;
4134 static const char* get_opentype_script(const GdiFont *font)
4137 * I am not sure if this is the correct way to generate our script tag
4140 switch (font->charset)
4142 case ANSI_CHARSET: return "latn";
4143 case BALTIC_CHARSET: return "latn"; /* ?? */
4144 case CHINESEBIG5_CHARSET: return "hani";
4145 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4146 case GB2312_CHARSET: return "hani";
4147 case GREEK_CHARSET: return "grek";
4148 case HANGUL_CHARSET: return "hang";
4149 case RUSSIAN_CHARSET: return "cyrl";
4150 case SHIFTJIS_CHARSET: return "kana";
4151 case TURKISH_CHARSET: return "latn"; /* ?? */
4152 case VIETNAMESE_CHARSET: return "latn";
4153 case JOHAB_CHARSET: return "latn"; /* ?? */
4154 case ARABIC_CHARSET: return "arab";
4155 case HEBREW_CHARSET: return "hebr";
4156 case THAI_CHARSET: return "thai";
4157 default: return "latn";
4161 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4163 const GSUB_Header *header;
4164 const GSUB_Script *script;
4165 const GSUB_LangSys *language;
4166 const GSUB_Feature *feature;
4168 if (!font->GSUB_Table)
4169 return glyph;
4171 header = font->GSUB_Table;
4173 script = GSUB_get_script_table(header, get_opentype_script(font));
4174 if (!script)
4176 TRACE("Script not found\n");
4177 return glyph;
4179 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4180 if (!language)
4182 TRACE("Language not found\n");
4183 return glyph;
4185 feature = GSUB_get_feature(header, language, "vrt2");
4186 if (!feature)
4187 feature = GSUB_get_feature(header, language, "vert");
4188 if (!feature)
4190 TRACE("vrt2/vert feature not found\n");
4191 return glyph;
4193 return GSUB_apply_feature(header, feature, glyph);
4196 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4198 FT_UInt glyphId;
4200 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4201 WCHAR wc = (WCHAR)glyph;
4202 BOOL default_used;
4203 BOOL *default_used_pointer;
4204 FT_UInt ret;
4205 char buf;
4206 default_used_pointer = NULL;
4207 default_used = FALSE;
4208 if (codepage_sets_default_used(font->codepage))
4209 default_used_pointer = &default_used;
4210 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4211 ret = 0;
4212 else
4213 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4214 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4215 return get_GSUB_vert_glyph(font,ret);
4218 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4219 glyph = glyph + 0xf000;
4220 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4221 return get_GSUB_vert_glyph(font,glyphId);
4224 /*************************************************************
4225 * WineEngGetGlyphIndices
4228 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4229 LPWORD pgi, DWORD flags)
4231 int i;
4232 int default_char = -1;
4234 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4236 for(i = 0; i < count; i++)
4238 pgi[i] = get_glyph_index(font, lpstr[i]);
4239 if (pgi[i] == 0)
4241 if (default_char == -1)
4243 if (FT_IS_SFNT(font->ft_face))
4245 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4246 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4248 else
4250 TEXTMETRICW textm;
4251 WineEngGetTextMetrics(font, &textm);
4252 default_char = textm.tmDefaultChar;
4255 pgi[i] = default_char;
4258 return count;
4261 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4263 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4264 return !memcmp(matrix, &identity, sizeof(FMAT2));
4267 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4269 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4270 return !memcmp(matrix, &identity, sizeof(MAT2));
4273 /*************************************************************
4274 * WineEngGetGlyphOutline
4276 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4277 * except that the first parameter is the HWINEENGFONT of the font in
4278 * question rather than an HDC.
4281 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4282 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4283 const MAT2* lpmat)
4285 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4286 FT_Face ft_face = incoming_font->ft_face;
4287 GdiFont *font = incoming_font;
4288 FT_UInt glyph_index;
4289 DWORD width, height, pitch, needed = 0;
4290 FT_Bitmap ft_bitmap;
4291 FT_Error err;
4292 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4293 FT_Angle angle = 0;
4294 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4295 double widthRatio = 1.0;
4296 FT_Matrix transMat = identityMat;
4297 BOOL needsTransform = FALSE;
4298 BOOL tategaki = (font->GSUB_Table != NULL);
4299 UINT original_index;
4301 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4302 buflen, buf, lpmat);
4304 TRACE("font transform %f %f %f %f\n",
4305 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4306 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4308 EnterCriticalSection( &freetype_cs );
4310 if(format & GGO_GLYPH_INDEX) {
4311 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4312 original_index = glyph;
4313 format &= ~GGO_GLYPH_INDEX;
4314 } else {
4315 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4316 ft_face = font->ft_face;
4317 original_index = glyph_index;
4320 /* tategaki never appears to happen to lower glyph index */
4321 if (glyph_index < TATEGAKI_LOWER_BOUND )
4322 tategaki = FALSE;
4324 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4325 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4326 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4327 font->gmsize * sizeof(GM*));
4328 } else {
4329 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4330 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4332 *lpgm = FONT_GM(font,original_index)->gm;
4333 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4334 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4335 lpgm->gmCellIncX, lpgm->gmCellIncY);
4336 LeaveCriticalSection( &freetype_cs );
4337 return 1; /* FIXME */
4341 if (!font->gm[original_index / GM_BLOCK_SIZE])
4342 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4344 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4345 load_flags |= FT_LOAD_NO_BITMAP;
4347 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4349 if(err) {
4350 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4351 LeaveCriticalSection( &freetype_cs );
4352 return GDI_ERROR;
4355 /* Scaling factor */
4356 if (font->aveWidth)
4358 TEXTMETRICW tm;
4360 WineEngGetTextMetrics(font, &tm);
4362 widthRatio = (double)font->aveWidth;
4363 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4365 else
4366 widthRatio = font->scale_y;
4368 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4369 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4371 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4372 lsb = left >> 6;
4373 bbx = (right - left) >> 6;
4375 /* Scaling transform */
4376 if (widthRatio != 1.0 || font->scale_y != 1.0)
4378 FT_Matrix scaleMat;
4379 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4380 scaleMat.xy = 0;
4381 scaleMat.yx = 0;
4382 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4384 pFT_Matrix_Multiply(&scaleMat, &transMat);
4385 needsTransform = TRUE;
4388 /* Slant transform */
4389 if (font->fake_italic) {
4390 FT_Matrix slantMat;
4392 slantMat.xx = (1 << 16);
4393 slantMat.xy = ((1 << 16) >> 2);
4394 slantMat.yx = 0;
4395 slantMat.yy = (1 << 16);
4396 pFT_Matrix_Multiply(&slantMat, &transMat);
4397 needsTransform = TRUE;
4400 /* Rotation transform */
4401 if(font->orientation && !tategaki) {
4402 FT_Matrix rotationMat;
4403 FT_Vector vecAngle;
4404 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4405 pFT_Vector_Unit(&vecAngle, angle);
4406 rotationMat.xx = vecAngle.x;
4407 rotationMat.xy = -vecAngle.y;
4408 rotationMat.yx = -rotationMat.xy;
4409 rotationMat.yy = rotationMat.xx;
4411 pFT_Matrix_Multiply(&rotationMat, &transMat);
4412 needsTransform = TRUE;
4415 /* World transform */
4416 if (!is_identity_FMAT2(&font->font_desc.matrix))
4418 FT_Matrix worldMat;
4419 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4420 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4421 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4422 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4423 pFT_Matrix_Multiply(&worldMat, &transMat);
4424 needsTransform = TRUE;
4427 /* Extra transformation specified by caller */
4428 if (lpmat && !is_identity_MAT2(lpmat))
4430 FT_Matrix extraMat;
4431 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4432 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4433 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4434 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4435 pFT_Matrix_Multiply(&extraMat, &transMat);
4436 needsTransform = TRUE;
4439 if(!needsTransform) {
4440 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4441 bottom = (ft_face->glyph->metrics.horiBearingY -
4442 ft_face->glyph->metrics.height) & -64;
4443 lpgm->gmCellIncX = adv;
4444 lpgm->gmCellIncY = 0;
4445 } else {
4446 INT xc, yc;
4447 FT_Vector vec;
4448 for(xc = 0; xc < 2; xc++) {
4449 for(yc = 0; yc < 2; yc++) {
4450 vec.x = (ft_face->glyph->metrics.horiBearingX +
4451 xc * ft_face->glyph->metrics.width);
4452 vec.y = ft_face->glyph->metrics.horiBearingY -
4453 yc * ft_face->glyph->metrics.height;
4454 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4455 pFT_Vector_Transform(&vec, &transMat);
4456 if(xc == 0 && yc == 0) {
4457 left = right = vec.x;
4458 top = bottom = vec.y;
4459 } else {
4460 if(vec.x < left) left = vec.x;
4461 else if(vec.x > right) right = vec.x;
4462 if(vec.y < bottom) bottom = vec.y;
4463 else if(vec.y > top) top = vec.y;
4467 left = left & -64;
4468 right = (right + 63) & -64;
4469 bottom = bottom & -64;
4470 top = (top + 63) & -64;
4472 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4473 vec.x = ft_face->glyph->metrics.horiAdvance;
4474 vec.y = 0;
4475 pFT_Vector_Transform(&vec, &transMat);
4476 adv = lpgm->gmCellIncX = (vec.x+63) >> 6;
4477 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4479 lpgm->gmBlackBoxX = (right - left) >> 6;
4480 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4481 lpgm->gmptGlyphOrigin.x = left >> 6;
4482 lpgm->gmptGlyphOrigin.y = top >> 6;
4484 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4485 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4486 lpgm->gmCellIncX, lpgm->gmCellIncY);
4488 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4489 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4491 FONT_GM(font,original_index)->gm = *lpgm;
4492 FONT_GM(font,original_index)->adv = adv;
4493 FONT_GM(font,original_index)->lsb = lsb;
4494 FONT_GM(font,original_index)->bbx = bbx;
4495 FONT_GM(font,original_index)->init = TRUE;
4498 if(format == GGO_METRICS)
4500 LeaveCriticalSection( &freetype_cs );
4501 return 1; /* FIXME */
4504 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4505 TRACE("loaded a bitmap\n");
4506 LeaveCriticalSection( &freetype_cs );
4507 return GDI_ERROR;
4510 switch(format) {
4511 case GGO_BITMAP:
4512 width = lpgm->gmBlackBoxX;
4513 height = lpgm->gmBlackBoxY;
4514 pitch = ((width + 31) >> 5) << 2;
4515 needed = pitch * height;
4517 if(!buf || !buflen) break;
4519 switch(ft_face->glyph->format) {
4520 case ft_glyph_format_bitmap:
4522 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4523 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4524 INT h = ft_face->glyph->bitmap.rows;
4525 while(h--) {
4526 memcpy(dst, src, w);
4527 src += ft_face->glyph->bitmap.pitch;
4528 dst += pitch;
4530 break;
4533 case ft_glyph_format_outline:
4534 ft_bitmap.width = width;
4535 ft_bitmap.rows = height;
4536 ft_bitmap.pitch = pitch;
4537 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4538 ft_bitmap.buffer = buf;
4540 if(needsTransform) {
4541 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4544 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4546 /* Note: FreeType will only set 'black' bits for us. */
4547 memset(buf, 0, needed);
4548 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4549 break;
4551 default:
4552 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4553 LeaveCriticalSection( &freetype_cs );
4554 return GDI_ERROR;
4556 break;
4558 case GGO_GRAY2_BITMAP:
4559 case GGO_GRAY4_BITMAP:
4560 case GGO_GRAY8_BITMAP:
4561 case WINE_GGO_GRAY16_BITMAP:
4563 unsigned int mult, row, col;
4564 BYTE *start, *ptr;
4566 width = lpgm->gmBlackBoxX;
4567 height = lpgm->gmBlackBoxY;
4568 pitch = (width + 3) / 4 * 4;
4569 needed = pitch * height;
4571 if(!buf || !buflen) break;
4573 switch(ft_face->glyph->format) {
4574 case ft_glyph_format_bitmap:
4576 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4577 INT h = ft_face->glyph->bitmap.rows;
4578 INT x;
4579 while(h--) {
4580 for(x = 0; x < pitch; x++)
4582 if(x < ft_face->glyph->bitmap.width)
4583 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4584 else
4585 dst[x] = 0;
4587 src += ft_face->glyph->bitmap.pitch;
4588 dst += pitch;
4590 LeaveCriticalSection( &freetype_cs );
4591 return needed;
4593 case ft_glyph_format_outline:
4595 ft_bitmap.width = width;
4596 ft_bitmap.rows = height;
4597 ft_bitmap.pitch = pitch;
4598 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4599 ft_bitmap.buffer = buf;
4601 if(needsTransform)
4602 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4604 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4606 memset(ft_bitmap.buffer, 0, buflen);
4608 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4610 if(format == GGO_GRAY2_BITMAP)
4611 mult = 4;
4612 else if(format == GGO_GRAY4_BITMAP)
4613 mult = 16;
4614 else if(format == GGO_GRAY8_BITMAP)
4615 mult = 64;
4616 else /* format == WINE_GGO_GRAY16_BITMAP */
4618 LeaveCriticalSection( &freetype_cs );
4619 return needed;
4621 break;
4623 default:
4624 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4625 LeaveCriticalSection( &freetype_cs );
4626 return GDI_ERROR;
4629 start = buf;
4630 for(row = 0; row < height; row++) {
4631 ptr = start;
4632 for(col = 0; col < width; col++, ptr++) {
4633 *ptr = (((int)*ptr) * mult + 128) / 256;
4635 start += pitch;
4637 break;
4640 case GGO_NATIVE:
4642 int contour, point = 0, first_pt;
4643 FT_Outline *outline = &ft_face->glyph->outline;
4644 TTPOLYGONHEADER *pph;
4645 TTPOLYCURVE *ppc;
4646 DWORD pph_start, cpfx, type;
4648 if(buflen == 0) buf = NULL;
4650 if (needsTransform && buf) {
4651 pFT_Outline_Transform(outline, &transMat);
4654 for(contour = 0; contour < outline->n_contours; contour++) {
4655 pph_start = needed;
4656 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4657 first_pt = point;
4658 if(buf) {
4659 pph->dwType = TT_POLYGON_TYPE;
4660 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4662 needed += sizeof(*pph);
4663 point++;
4664 while(point <= outline->contours[contour]) {
4665 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4666 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4667 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4668 cpfx = 0;
4669 do {
4670 if(buf)
4671 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4672 cpfx++;
4673 point++;
4674 } while(point <= outline->contours[contour] &&
4675 (outline->tags[point] & FT_Curve_Tag_On) ==
4676 (outline->tags[point-1] & FT_Curve_Tag_On));
4677 /* At the end of a contour Windows adds the start point, but
4678 only for Beziers */
4679 if(point > outline->contours[contour] &&
4680 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4681 if(buf)
4682 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4683 cpfx++;
4684 } else if(point <= outline->contours[contour] &&
4685 outline->tags[point] & FT_Curve_Tag_On) {
4686 /* add closing pt for bezier */
4687 if(buf)
4688 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4689 cpfx++;
4690 point++;
4692 if(buf) {
4693 ppc->wType = type;
4694 ppc->cpfx = cpfx;
4696 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4698 if(buf)
4699 pph->cb = needed - pph_start;
4701 break;
4703 case GGO_BEZIER:
4705 /* Convert the quadratic Beziers to cubic Beziers.
4706 The parametric eqn for a cubic Bezier is, from PLRM:
4707 r(t) = at^3 + bt^2 + ct + r0
4708 with the control points:
4709 r1 = r0 + c/3
4710 r2 = r1 + (c + b)/3
4711 r3 = r0 + c + b + a
4713 A quadratic Beizer has the form:
4714 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4716 So equating powers of t leads to:
4717 r1 = 2/3 p1 + 1/3 p0
4718 r2 = 2/3 p1 + 1/3 p2
4719 and of course r0 = p0, r3 = p2
4722 int contour, point = 0, first_pt;
4723 FT_Outline *outline = &ft_face->glyph->outline;
4724 TTPOLYGONHEADER *pph;
4725 TTPOLYCURVE *ppc;
4726 DWORD pph_start, cpfx, type;
4727 FT_Vector cubic_control[4];
4728 if(buflen == 0) buf = NULL;
4730 if (needsTransform && buf) {
4731 pFT_Outline_Transform(outline, &transMat);
4734 for(contour = 0; contour < outline->n_contours; contour++) {
4735 pph_start = needed;
4736 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4737 first_pt = point;
4738 if(buf) {
4739 pph->dwType = TT_POLYGON_TYPE;
4740 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4742 needed += sizeof(*pph);
4743 point++;
4744 while(point <= outline->contours[contour]) {
4745 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4746 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4747 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4748 cpfx = 0;
4749 do {
4750 if(type == TT_PRIM_LINE) {
4751 if(buf)
4752 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4753 cpfx++;
4754 point++;
4755 } else {
4756 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4757 so cpfx = 3n */
4759 /* FIXME: Possible optimization in endpoint calculation
4760 if there are two consecutive curves */
4761 cubic_control[0] = outline->points[point-1];
4762 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4763 cubic_control[0].x += outline->points[point].x + 1;
4764 cubic_control[0].y += outline->points[point].y + 1;
4765 cubic_control[0].x >>= 1;
4766 cubic_control[0].y >>= 1;
4768 if(point+1 > outline->contours[contour])
4769 cubic_control[3] = outline->points[first_pt];
4770 else {
4771 cubic_control[3] = outline->points[point+1];
4772 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4773 cubic_control[3].x += outline->points[point].x + 1;
4774 cubic_control[3].y += outline->points[point].y + 1;
4775 cubic_control[3].x >>= 1;
4776 cubic_control[3].y >>= 1;
4779 /* r1 = 1/3 p0 + 2/3 p1
4780 r2 = 1/3 p2 + 2/3 p1 */
4781 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4782 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4783 cubic_control[2] = cubic_control[1];
4784 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4785 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4786 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4787 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4788 if(buf) {
4789 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4790 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4791 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4793 cpfx += 3;
4794 point++;
4796 } while(point <= outline->contours[contour] &&
4797 (outline->tags[point] & FT_Curve_Tag_On) ==
4798 (outline->tags[point-1] & FT_Curve_Tag_On));
4799 /* At the end of a contour Windows adds the start point,
4800 but only for Beziers and we've already done that.
4802 if(point <= outline->contours[contour] &&
4803 outline->tags[point] & FT_Curve_Tag_On) {
4804 /* This is the closing pt of a bezier, but we've already
4805 added it, so just inc point and carry on */
4806 point++;
4808 if(buf) {
4809 ppc->wType = type;
4810 ppc->cpfx = cpfx;
4812 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4814 if(buf)
4815 pph->cb = needed - pph_start;
4817 break;
4820 default:
4821 FIXME("Unsupported format %d\n", format);
4822 LeaveCriticalSection( &freetype_cs );
4823 return GDI_ERROR;
4825 LeaveCriticalSection( &freetype_cs );
4826 return needed;
4829 static BOOL get_bitmap_text_metrics(GdiFont *font)
4831 FT_Face ft_face = font->ft_face;
4832 #ifdef HAVE_FREETYPE_FTWINFNT_H
4833 FT_WinFNT_HeaderRec winfnt_header;
4834 #endif
4835 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4836 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4837 font->potm->otmSize = size;
4839 #define TM font->potm->otmTextMetrics
4840 #ifdef HAVE_FREETYPE_FTWINFNT_H
4841 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4843 TM.tmHeight = winfnt_header.pixel_height;
4844 TM.tmAscent = winfnt_header.ascent;
4845 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4846 TM.tmInternalLeading = winfnt_header.internal_leading;
4847 TM.tmExternalLeading = winfnt_header.external_leading;
4848 TM.tmAveCharWidth = winfnt_header.avg_width;
4849 TM.tmMaxCharWidth = winfnt_header.max_width;
4850 TM.tmWeight = winfnt_header.weight;
4851 TM.tmOverhang = 0;
4852 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4853 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4854 TM.tmFirstChar = winfnt_header.first_char;
4855 TM.tmLastChar = winfnt_header.last_char;
4856 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4857 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4858 TM.tmItalic = winfnt_header.italic;
4859 TM.tmUnderlined = font->underline;
4860 TM.tmStruckOut = font->strikeout;
4861 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4862 TM.tmCharSet = winfnt_header.charset;
4864 else
4865 #endif
4867 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4868 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4869 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4870 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4871 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4872 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4873 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4874 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4875 TM.tmOverhang = 0;
4876 TM.tmDigitizedAspectX = 96; /* FIXME */
4877 TM.tmDigitizedAspectY = 96; /* FIXME */
4878 TM.tmFirstChar = 1;
4879 TM.tmLastChar = 255;
4880 TM.tmDefaultChar = 32;
4881 TM.tmBreakChar = 32;
4882 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4883 TM.tmUnderlined = font->underline;
4884 TM.tmStruckOut = font->strikeout;
4885 /* NB inverted meaning of TMPF_FIXED_PITCH */
4886 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4887 TM.tmCharSet = font->charset;
4889 #undef TM
4891 return TRUE;
4895 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4897 double scale_x, scale_y;
4899 if (font->aveWidth)
4901 scale_x = (double)font->aveWidth;
4902 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4904 else
4905 scale_x = font->scale_y;
4907 scale_x *= fabs(font->font_desc.matrix.eM11);
4908 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4910 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4911 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4913 SCALE_Y(ptm->tmHeight);
4914 SCALE_Y(ptm->tmAscent);
4915 SCALE_Y(ptm->tmDescent);
4916 SCALE_Y(ptm->tmInternalLeading);
4917 SCALE_Y(ptm->tmExternalLeading);
4918 SCALE_Y(ptm->tmOverhang);
4920 SCALE_X(ptm->tmAveCharWidth);
4921 SCALE_X(ptm->tmMaxCharWidth);
4923 #undef SCALE_X
4924 #undef SCALE_Y
4927 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4929 double scale_x, scale_y;
4931 if (font->aveWidth)
4933 scale_x = (double)font->aveWidth;
4934 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4936 else
4937 scale_x = font->scale_y;
4939 scale_x *= fabs(font->font_desc.matrix.eM11);
4940 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4942 scale_font_metrics(font, &potm->otmTextMetrics);
4944 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4945 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4947 SCALE_Y(potm->otmAscent);
4948 SCALE_Y(potm->otmDescent);
4949 SCALE_Y(potm->otmLineGap);
4950 SCALE_Y(potm->otmsCapEmHeight);
4951 SCALE_Y(potm->otmsXHeight);
4952 SCALE_Y(potm->otmrcFontBox.top);
4953 SCALE_Y(potm->otmrcFontBox.bottom);
4954 SCALE_X(potm->otmrcFontBox.left);
4955 SCALE_X(potm->otmrcFontBox.right);
4956 SCALE_Y(potm->otmMacAscent);
4957 SCALE_Y(potm->otmMacDescent);
4958 SCALE_Y(potm->otmMacLineGap);
4959 SCALE_X(potm->otmptSubscriptSize.x);
4960 SCALE_Y(potm->otmptSubscriptSize.y);
4961 SCALE_X(potm->otmptSubscriptOffset.x);
4962 SCALE_Y(potm->otmptSubscriptOffset.y);
4963 SCALE_X(potm->otmptSuperscriptSize.x);
4964 SCALE_Y(potm->otmptSuperscriptSize.y);
4965 SCALE_X(potm->otmptSuperscriptOffset.x);
4966 SCALE_Y(potm->otmptSuperscriptOffset.y);
4967 SCALE_Y(potm->otmsStrikeoutSize);
4968 SCALE_Y(potm->otmsStrikeoutPosition);
4969 SCALE_Y(potm->otmsUnderscoreSize);
4970 SCALE_Y(potm->otmsUnderscorePosition);
4972 #undef SCALE_X
4973 #undef SCALE_Y
4976 /*************************************************************
4977 * WineEngGetTextMetrics
4980 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4982 EnterCriticalSection( &freetype_cs );
4983 if(!font->potm) {
4984 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4985 if(!get_bitmap_text_metrics(font))
4987 LeaveCriticalSection( &freetype_cs );
4988 return FALSE;
4991 if(!font->potm)
4993 LeaveCriticalSection( &freetype_cs );
4994 return FALSE;
4996 *ptm = font->potm->otmTextMetrics;
4997 scale_font_metrics(font, ptm);
4998 LeaveCriticalSection( &freetype_cs );
4999 return TRUE;
5003 /*************************************************************
5004 * WineEngGetOutlineTextMetrics
5007 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5008 OUTLINETEXTMETRICW *potm)
5010 FT_Face ft_face = font->ft_face;
5011 UINT needed, lenfam, lensty, ret;
5012 TT_OS2 *pOS2;
5013 TT_HoriHeader *pHori;
5014 TT_Postscript *pPost;
5015 FT_Fixed x_scale, y_scale;
5016 WCHAR *family_nameW, *style_nameW;
5017 static const WCHAR spaceW[] = {' ', '\0'};
5018 char *cp;
5019 INT ascent, descent;
5021 TRACE("font=%p\n", font);
5023 if(!FT_IS_SCALABLE(ft_face))
5024 return 0;
5026 EnterCriticalSection( &freetype_cs );
5028 if(font->potm) {
5029 if(cbSize >= font->potm->otmSize)
5031 memcpy(potm, font->potm, font->potm->otmSize);
5032 scale_outline_font_metrics(font, potm);
5034 LeaveCriticalSection( &freetype_cs );
5035 return font->potm->otmSize;
5039 needed = sizeof(*potm);
5041 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5042 family_nameW = strdupW(font->name);
5044 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5045 * sizeof(WCHAR);
5046 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5047 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5048 style_nameW, lensty/sizeof(WCHAR));
5050 /* These names should be read from the TT name table */
5052 /* length of otmpFamilyName */
5053 needed += lenfam;
5055 /* length of otmpFaceName */
5056 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5057 needed += lenfam; /* just the family name */
5058 } else {
5059 needed += lenfam + lensty; /* family + " " + style */
5062 /* length of otmpStyleName */
5063 needed += lensty;
5065 /* length of otmpFullName */
5066 needed += lenfam + lensty;
5069 x_scale = ft_face->size->metrics.x_scale;
5070 y_scale = ft_face->size->metrics.y_scale;
5072 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5073 if(!pOS2) {
5074 FIXME("Can't find OS/2 table - not TT font?\n");
5075 ret = 0;
5076 goto end;
5079 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5080 if(!pHori) {
5081 FIXME("Can't find HHEA table - not TT font?\n");
5082 ret = 0;
5083 goto end;
5086 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5088 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",
5089 pOS2->usWinAscent, pOS2->usWinDescent,
5090 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5091 ft_face->ascender, ft_face->descender, ft_face->height,
5092 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5093 ft_face->bbox.yMax, ft_face->bbox.yMin);
5095 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5096 font->potm->otmSize = needed;
5098 #define TM font->potm->otmTextMetrics
5100 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5101 ascent = pHori->Ascender;
5102 descent = -pHori->Descender;
5103 } else {
5104 ascent = pOS2->usWinAscent;
5105 descent = pOS2->usWinDescent;
5108 if(font->yMax) {
5109 TM.tmAscent = font->yMax;
5110 TM.tmDescent = -font->yMin;
5111 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5112 } else {
5113 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5114 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5115 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5116 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5119 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5121 /* MSDN says:
5122 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5124 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5125 ((ascent + descent) -
5126 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5128 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5129 if (TM.tmAveCharWidth == 0) {
5130 TM.tmAveCharWidth = 1;
5132 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5133 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
5134 TM.tmOverhang = 0;
5135 TM.tmDigitizedAspectX = 300;
5136 TM.tmDigitizedAspectY = 300;
5137 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5138 * symbol range to 0 - f0ff
5140 if (font->charset == SYMBOL_CHARSET)
5142 TM.tmFirstChar = 0;
5143 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5145 else
5147 TM.tmFirstChar = pOS2->usFirstCharIndex;
5148 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5150 TM.tmLastChar = pOS2->usLastCharIndex;
5151 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5152 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5153 TM.tmUnderlined = font->underline;
5154 TM.tmStruckOut = font->strikeout;
5156 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5157 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5158 (pOS2->version == 0xFFFFU ||
5159 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5160 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5161 else
5162 TM.tmPitchAndFamily = 0;
5164 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5165 case PAN_FAMILY_SCRIPT:
5166 TM.tmPitchAndFamily |= FF_SCRIPT;
5167 break;
5168 case PAN_FAMILY_DECORATIVE:
5169 case PAN_FAMILY_PICTORIAL:
5170 TM.tmPitchAndFamily |= FF_DECORATIVE;
5171 break;
5172 case PAN_FAMILY_TEXT_DISPLAY:
5173 if(TM.tmPitchAndFamily == 0) /* fixed */
5174 TM.tmPitchAndFamily = FF_MODERN;
5175 else {
5176 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5177 case PAN_SERIF_NORMAL_SANS:
5178 case PAN_SERIF_OBTUSE_SANS:
5179 case PAN_SERIF_PERP_SANS:
5180 TM.tmPitchAndFamily |= FF_SWISS;
5181 break;
5182 default:
5183 TM.tmPitchAndFamily |= FF_ROMAN;
5186 break;
5187 default:
5188 TM.tmPitchAndFamily |= FF_DONTCARE;
5191 if(FT_IS_SCALABLE(ft_face))
5192 TM.tmPitchAndFamily |= TMPF_VECTOR;
5194 if(FT_IS_SFNT(ft_face))
5196 if (font->ntmFlags & NTM_PS_OPENTYPE)
5197 TM.tmPitchAndFamily |= TMPF_DEVICE;
5198 else
5199 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5202 TM.tmCharSet = font->charset;
5204 font->potm->otmFiller = 0;
5205 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5206 font->potm->otmfsSelection = pOS2->fsSelection;
5207 font->potm->otmfsType = pOS2->fsType;
5208 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5209 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5210 font->potm->otmItalicAngle = 0; /* POST table */
5211 font->potm->otmEMSquare = ft_face->units_per_EM;
5212 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5213 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5214 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5215 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5216 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5217 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5218 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5219 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5220 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5221 font->potm->otmMacAscent = TM.tmAscent;
5222 font->potm->otmMacDescent = -TM.tmDescent;
5223 font->potm->otmMacLineGap = font->potm->otmLineGap;
5224 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5225 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5226 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5227 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5228 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5229 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5230 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5231 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5232 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5233 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5234 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5235 if(!pPost) {
5236 font->potm->otmsUnderscoreSize = 0;
5237 font->potm->otmsUnderscorePosition = 0;
5238 } else {
5239 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5240 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5242 #undef TM
5244 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5245 cp = (char*)font->potm + sizeof(*font->potm);
5246 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5247 strcpyW((WCHAR*)cp, family_nameW);
5248 cp += lenfam;
5249 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5250 strcpyW((WCHAR*)cp, style_nameW);
5251 cp += lensty;
5252 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5253 strcpyW((WCHAR*)cp, family_nameW);
5254 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5255 strcatW((WCHAR*)cp, spaceW);
5256 strcatW((WCHAR*)cp, style_nameW);
5257 cp += lenfam + lensty;
5258 } else
5259 cp += lenfam;
5260 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5261 strcpyW((WCHAR*)cp, family_nameW);
5262 strcatW((WCHAR*)cp, spaceW);
5263 strcatW((WCHAR*)cp, style_nameW);
5264 ret = needed;
5266 if(potm && needed <= cbSize)
5268 memcpy(potm, font->potm, font->potm->otmSize);
5269 scale_outline_font_metrics(font, potm);
5272 end:
5273 HeapFree(GetProcessHeap(), 0, style_nameW);
5274 HeapFree(GetProcessHeap(), 0, family_nameW);
5276 LeaveCriticalSection( &freetype_cs );
5277 return ret;
5280 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5282 HFONTLIST *hfontlist;
5283 child->font = alloc_font();
5284 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5285 if(!child->font->ft_face)
5287 free_font(child->font);
5288 child->font = NULL;
5289 return FALSE;
5292 child->font->ntmFlags = child->face->ntmFlags;
5293 child->font->orientation = font->orientation;
5294 child->font->scale_y = font->scale_y;
5295 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5296 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5297 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5298 child->font->base_font = font;
5299 list_add_head(&child_font_list, &child->font->entry);
5300 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5301 return TRUE;
5304 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5306 FT_UInt g;
5307 CHILD_FONT *child_font;
5309 if(font->base_font)
5310 font = font->base_font;
5312 *linked_font = font;
5314 if((*glyph = get_glyph_index(font, c)))
5315 return TRUE;
5317 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5319 if(!child_font->font)
5320 if(!load_child_font(font, child_font))
5321 continue;
5323 if(!child_font->font->ft_face)
5324 continue;
5325 g = get_glyph_index(child_font->font, c);
5326 if(g)
5328 *glyph = g;
5329 *linked_font = child_font->font;
5330 return TRUE;
5333 return FALSE;
5336 /*************************************************************
5337 * WineEngGetCharWidth
5340 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5341 LPINT buffer)
5343 UINT c;
5344 GLYPHMETRICS gm;
5345 FT_UInt glyph_index;
5346 GdiFont *linked_font;
5348 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5350 EnterCriticalSection( &freetype_cs );
5351 for(c = firstChar; c <= lastChar; c++) {
5352 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5353 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5354 &gm, 0, NULL, NULL);
5355 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5357 LeaveCriticalSection( &freetype_cs );
5358 return TRUE;
5361 /*************************************************************
5362 * WineEngGetCharABCWidths
5365 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5366 LPABC buffer)
5368 UINT c;
5369 GLYPHMETRICS gm;
5370 FT_UInt glyph_index;
5371 GdiFont *linked_font;
5373 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5375 if(!FT_IS_SCALABLE(font->ft_face))
5376 return FALSE;
5378 EnterCriticalSection( &freetype_cs );
5380 for(c = firstChar; c <= lastChar; c++) {
5381 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5382 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5383 &gm, 0, NULL, NULL);
5384 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5385 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5386 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5387 FONT_GM(linked_font,glyph_index)->bbx;
5389 LeaveCriticalSection( &freetype_cs );
5390 return TRUE;
5393 /*************************************************************
5394 * WineEngGetCharABCWidthsI
5397 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5398 LPABC buffer)
5400 UINT c;
5401 GLYPHMETRICS gm;
5402 FT_UInt glyph_index;
5403 GdiFont *linked_font;
5405 if(!FT_HAS_HORIZONTAL(font->ft_face))
5406 return FALSE;
5408 EnterCriticalSection( &freetype_cs );
5410 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5411 if (!pgi)
5412 for(c = firstChar; c < firstChar+count; c++) {
5413 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5414 &gm, 0, NULL, NULL);
5415 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5416 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5417 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5418 - FONT_GM(linked_font,c)->bbx;
5420 else
5421 for(c = 0; c < count; c++) {
5422 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5423 &gm, 0, NULL, NULL);
5424 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5425 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5426 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5427 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5430 LeaveCriticalSection( &freetype_cs );
5431 return TRUE;
5434 /*************************************************************
5435 * WineEngGetTextExtentExPoint
5438 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5439 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5441 INT idx;
5442 INT nfit = 0, ext;
5443 GLYPHMETRICS gm;
5444 TEXTMETRICW tm;
5445 FT_UInt glyph_index;
5446 GdiFont *linked_font;
5448 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5449 max_ext, size);
5451 EnterCriticalSection( &freetype_cs );
5453 size->cx = 0;
5454 WineEngGetTextMetrics(font, &tm);
5455 size->cy = tm.tmHeight;
5457 for(idx = 0; idx < count; idx++) {
5458 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5459 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5460 &gm, 0, NULL, NULL);
5461 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5462 ext = size->cx;
5463 if (! pnfit || ext <= max_ext) {
5464 ++nfit;
5465 if (dxs)
5466 dxs[idx] = ext;
5470 if (pnfit)
5471 *pnfit = nfit;
5473 LeaveCriticalSection( &freetype_cs );
5474 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5475 return TRUE;
5478 /*************************************************************
5479 * WineEngGetTextExtentExPointI
5482 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5483 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5485 INT idx;
5486 INT nfit = 0, ext;
5487 GLYPHMETRICS gm;
5488 TEXTMETRICW tm;
5490 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5492 EnterCriticalSection( &freetype_cs );
5494 size->cx = 0;
5495 WineEngGetTextMetrics(font, &tm);
5496 size->cy = tm.tmHeight;
5498 for(idx = 0; idx < count; idx++) {
5499 WineEngGetGlyphOutline(font, indices[idx],
5500 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5501 NULL);
5502 size->cx += FONT_GM(font,indices[idx])->adv;
5503 ext = size->cx;
5504 if (! pnfit || ext <= max_ext) {
5505 ++nfit;
5506 if (dxs)
5507 dxs[idx] = ext;
5511 if (pnfit)
5512 *pnfit = nfit;
5514 LeaveCriticalSection( &freetype_cs );
5515 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5516 return TRUE;
5519 /*************************************************************
5520 * WineEngGetFontData
5523 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5524 DWORD cbData)
5526 FT_Face ft_face = font->ft_face;
5527 FT_ULong len;
5528 FT_Error err;
5530 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5531 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5532 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5534 if(!FT_IS_SFNT(ft_face))
5535 return GDI_ERROR;
5537 if(!buf || !cbData)
5538 len = 0;
5539 else
5540 len = cbData;
5542 if(table) { /* MS tags differ in endianness from FT ones */
5543 table = table >> 24 | table << 24 |
5544 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5547 /* make sure value of len is the value freetype says it needs */
5548 if(buf && len)
5550 FT_ULong needed = 0;
5551 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5552 if( !err && needed < len) len = needed;
5554 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5556 if(err) {
5557 TRACE("Can't find table %c%c%c%c\n",
5558 /* bytes were reversed */
5559 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5560 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5561 return GDI_ERROR;
5563 return len;
5566 /*************************************************************
5567 * WineEngGetTextFace
5570 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5572 INT n = strlenW(font->name) + 1;
5573 if(str) {
5574 lstrcpynW(str, font->name, count);
5575 return min(count, n);
5576 } else
5577 return n;
5580 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5582 if (fs) *fs = font->fs;
5583 return font->charset;
5586 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5588 GdiFont *font = dc->gdiFont, *linked_font;
5589 struct list *first_hfont;
5590 BOOL ret;
5592 EnterCriticalSection( &freetype_cs );
5593 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5594 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5595 if(font == linked_font)
5596 *new_hfont = dc->hFont;
5597 else
5599 first_hfont = list_head(&linked_font->hfontlist);
5600 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5602 LeaveCriticalSection( &freetype_cs );
5603 return ret;
5606 /* Retrieve a list of supported Unicode ranges for a given font.
5607 * Can be called with NULL gs to calculate the buffer size. Returns
5608 * the number of ranges found.
5610 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5612 DWORD num_ranges = 0;
5614 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5616 FT_UInt glyph_code;
5617 FT_ULong char_code, char_code_prev;
5619 glyph_code = 0;
5620 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5622 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5623 face->num_glyphs, glyph_code, char_code);
5625 if (!glyph_code) return 0;
5627 if (gs)
5629 gs->ranges[0].wcLow = (USHORT)char_code;
5630 gs->ranges[0].cGlyphs = 0;
5631 gs->cGlyphsSupported = 0;
5634 num_ranges = 1;
5635 while (glyph_code)
5637 if (char_code < char_code_prev)
5639 ERR("expected increasing char code from FT_Get_Next_Char\n");
5640 return 0;
5642 if (char_code - char_code_prev > 1)
5644 num_ranges++;
5645 if (gs)
5647 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5648 gs->ranges[num_ranges - 1].cGlyphs = 1;
5649 gs->cGlyphsSupported++;
5652 else if (gs)
5654 gs->ranges[num_ranges - 1].cGlyphs++;
5655 gs->cGlyphsSupported++;
5657 char_code_prev = char_code;
5658 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5661 else
5662 FIXME("encoding %u not supported\n", face->charmap->encoding);
5664 return num_ranges;
5667 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5669 DWORD size = 0;
5670 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5672 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5673 if (glyphset)
5675 glyphset->cbThis = size;
5676 glyphset->cRanges = num_ranges;
5678 return size;
5681 /*************************************************************
5682 * FontIsLinked
5684 BOOL WineEngFontIsLinked(GdiFont *font)
5686 BOOL ret;
5687 EnterCriticalSection( &freetype_cs );
5688 ret = !list_empty(&font->child_fonts);
5689 LeaveCriticalSection( &freetype_cs );
5690 return ret;
5693 static BOOL is_hinting_enabled(void)
5695 /* Use the >= 2.2.0 function if available */
5696 if(pFT_Get_TrueType_Engine_Type)
5698 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5699 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5701 #ifdef FT_DRIVER_HAS_HINTER
5702 else
5704 FT_Module mod;
5706 /* otherwise if we've been compiled with < 2.2.0 headers
5707 use the internal macro */
5708 mod = pFT_Get_Module(library, "truetype");
5709 if(mod && FT_DRIVER_HAS_HINTER(mod))
5710 return TRUE;
5712 #endif
5714 return FALSE;
5717 /*************************************************************************
5718 * GetRasterizerCaps (GDI32.@)
5720 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5722 static int hinting = -1;
5724 if(hinting == -1)
5726 hinting = is_hinting_enabled();
5727 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5730 lprs->nSize = sizeof(RASTERIZER_STATUS);
5731 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5732 lprs->nLanguageID = 0;
5733 return TRUE;
5736 /*************************************************************************
5737 * Kerning support for TrueType fonts
5739 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5741 struct TT_kern_table
5743 USHORT version;
5744 USHORT nTables;
5747 struct TT_kern_subtable
5749 USHORT version;
5750 USHORT length;
5751 union
5753 USHORT word;
5754 struct
5756 USHORT horizontal : 1;
5757 USHORT minimum : 1;
5758 USHORT cross_stream: 1;
5759 USHORT override : 1;
5760 USHORT reserved1 : 4;
5761 USHORT format : 8;
5762 } bits;
5763 } coverage;
5766 struct TT_format0_kern_subtable
5768 USHORT nPairs;
5769 USHORT searchRange;
5770 USHORT entrySelector;
5771 USHORT rangeShift;
5774 struct TT_kern_pair
5776 USHORT left;
5777 USHORT right;
5778 short value;
5781 static DWORD parse_format0_kern_subtable(GdiFont *font,
5782 const struct TT_format0_kern_subtable *tt_f0_ks,
5783 const USHORT *glyph_to_char,
5784 KERNINGPAIR *kern_pair, DWORD cPairs)
5786 USHORT i, nPairs;
5787 const struct TT_kern_pair *tt_kern_pair;
5789 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5791 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5793 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5794 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5795 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5797 if (!kern_pair || !cPairs)
5798 return nPairs;
5800 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5802 nPairs = min(nPairs, cPairs);
5804 for (i = 0; i < nPairs; i++)
5806 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5807 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5808 /* this algorithm appears to better match what Windows does */
5809 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5810 if (kern_pair->iKernAmount < 0)
5812 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5813 kern_pair->iKernAmount -= font->ppem;
5815 else if (kern_pair->iKernAmount > 0)
5817 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5818 kern_pair->iKernAmount += font->ppem;
5820 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5822 TRACE("left %u right %u value %d\n",
5823 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5825 kern_pair++;
5827 TRACE("copied %u entries\n", nPairs);
5828 return nPairs;
5831 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5833 DWORD length;
5834 void *buf;
5835 const struct TT_kern_table *tt_kern_table;
5836 const struct TT_kern_subtable *tt_kern_subtable;
5837 USHORT i, nTables;
5838 USHORT *glyph_to_char;
5840 EnterCriticalSection( &freetype_cs );
5841 if (font->total_kern_pairs != (DWORD)-1)
5843 if (cPairs && kern_pair)
5845 cPairs = min(cPairs, font->total_kern_pairs);
5846 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5847 LeaveCriticalSection( &freetype_cs );
5848 return cPairs;
5850 LeaveCriticalSection( &freetype_cs );
5851 return font->total_kern_pairs;
5854 font->total_kern_pairs = 0;
5856 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5858 if (length == GDI_ERROR)
5860 TRACE("no kerning data in the font\n");
5861 LeaveCriticalSection( &freetype_cs );
5862 return 0;
5865 buf = HeapAlloc(GetProcessHeap(), 0, length);
5866 if (!buf)
5868 WARN("Out of memory\n");
5869 LeaveCriticalSection( &freetype_cs );
5870 return 0;
5873 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5875 /* build a glyph index to char code map */
5876 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5877 if (!glyph_to_char)
5879 WARN("Out of memory allocating a glyph index to char code map\n");
5880 HeapFree(GetProcessHeap(), 0, buf);
5881 LeaveCriticalSection( &freetype_cs );
5882 return 0;
5885 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5887 FT_UInt glyph_code;
5888 FT_ULong char_code;
5890 glyph_code = 0;
5891 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5893 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5894 font->ft_face->num_glyphs, glyph_code, char_code);
5896 while (glyph_code)
5898 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5900 /* FIXME: This doesn't match what Windows does: it does some fancy
5901 * things with duplicate glyph index to char code mappings, while
5902 * we just avoid overriding existing entries.
5904 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5905 glyph_to_char[glyph_code] = (USHORT)char_code;
5907 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5910 else
5912 ULONG n;
5914 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5915 for (n = 0; n <= 65535; n++)
5916 glyph_to_char[n] = (USHORT)n;
5919 tt_kern_table = buf;
5920 nTables = GET_BE_WORD(tt_kern_table->nTables);
5921 TRACE("version %u, nTables %u\n",
5922 GET_BE_WORD(tt_kern_table->version), nTables);
5924 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5926 for (i = 0; i < nTables; i++)
5928 struct TT_kern_subtable tt_kern_subtable_copy;
5930 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5931 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5932 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5934 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5935 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5936 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5938 /* According to the TrueType specification this is the only format
5939 * that will be properly interpreted by Windows and OS/2
5941 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5943 DWORD new_chunk, old_total = font->total_kern_pairs;
5945 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5946 glyph_to_char, NULL, 0);
5947 font->total_kern_pairs += new_chunk;
5949 if (!font->kern_pairs)
5950 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5951 font->total_kern_pairs * sizeof(*font->kern_pairs));
5952 else
5953 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5954 font->total_kern_pairs * sizeof(*font->kern_pairs));
5956 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5957 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5959 else
5960 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5962 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5965 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5966 HeapFree(GetProcessHeap(), 0, buf);
5968 if (cPairs && kern_pair)
5970 cPairs = min(cPairs, font->total_kern_pairs);
5971 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5972 LeaveCriticalSection( &freetype_cs );
5973 return cPairs;
5975 LeaveCriticalSection( &freetype_cs );
5976 return font->total_kern_pairs;
5979 #else /* HAVE_FREETYPE */
5981 /*************************************************************************/
5983 BOOL WineEngInit(void)
5985 return FALSE;
5987 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5989 return NULL;
5991 BOOL WineEngDestroyFontInstance(HFONT hfont)
5993 return FALSE;
5996 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5998 return 1;
6001 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6002 LPWORD pgi, DWORD flags)
6004 return GDI_ERROR;
6007 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6008 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6009 const MAT2* lpmat)
6011 ERR("called but we don't have FreeType\n");
6012 return GDI_ERROR;
6015 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6017 ERR("called but we don't have FreeType\n");
6018 return FALSE;
6021 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6022 OUTLINETEXTMETRICW *potm)
6024 ERR("called but we don't have FreeType\n");
6025 return 0;
6028 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6029 LPINT buffer)
6031 ERR("called but we don't have FreeType\n");
6032 return FALSE;
6035 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6036 LPABC buffer)
6038 ERR("called but we don't have FreeType\n");
6039 return FALSE;
6042 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6043 LPABC buffer)
6045 ERR("called but we don't have FreeType\n");
6046 return FALSE;
6049 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6050 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6052 ERR("called but we don't have FreeType\n");
6053 return FALSE;
6056 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6057 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6059 ERR("called but we don't have FreeType\n");
6060 return FALSE;
6063 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6064 DWORD cbData)
6066 ERR("called but we don't have FreeType\n");
6067 return GDI_ERROR;
6070 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6072 ERR("called but we don't have FreeType\n");
6073 return 0;
6076 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6078 FIXME(":stub\n");
6079 return 1;
6082 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6084 FIXME(":stub\n");
6085 return TRUE;
6088 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6090 FIXME(":stub\n");
6091 return NULL;
6094 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6096 FIXME(":stub\n");
6097 return DEFAULT_CHARSET;
6100 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6102 return FALSE;
6105 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6107 FIXME("(%p, %p): stub\n", font, glyphset);
6108 return 0;
6111 BOOL WineEngFontIsLinked(GdiFont *font)
6113 return FALSE;
6116 /*************************************************************************
6117 * GetRasterizerCaps (GDI32.@)
6119 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6121 lprs->nSize = sizeof(RASTERIZER_STATUS);
6122 lprs->wFlags = 0;
6123 lprs->nLanguageID = 0;
6124 return TRUE;
6127 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6129 ERR("called but we don't have FreeType\n");
6130 return 0;
6133 #endif /* HAVE_FREETYPE */