push 9758e6fe7ae8fbab538c98c718d6619029bb3457
[wine/hacks.git] / dlls / gdi32 / freetype.c
bloba2110ab970025747d9c15d41686890eb3afeaa39
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 double. It fails if the absolute
807 value of the float number is greater than 32768.
809 static inline FT_Fixed FT_FixedFromFloat(double f)
811 return f * 0x10000;
815 This function builds an FT_Fixed from a FIXED. It simply put f.value
816 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
818 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
820 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
824 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
826 Family *family;
827 Face *face;
828 const char *file;
829 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
830 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
832 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
833 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
835 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
837 if(face_name && strcmpiW(face_name, family->FamilyName))
838 continue;
839 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
841 if (!face->file)
842 continue;
843 file = strrchr(face->file, '/');
844 if(!file)
845 file = face->file;
846 else
847 file++;
848 if(!strcasecmp(file, file_nameA))
850 HeapFree(GetProcessHeap(), 0, file_nameA);
851 return face;
855 HeapFree(GetProcessHeap(), 0, file_nameA);
856 return NULL;
859 static Family *find_family_from_name(const WCHAR *name)
861 Family *family;
863 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
865 if(!strcmpiW(family->FamilyName, name))
866 return family;
869 return NULL;
872 static void DumpSubstList(void)
874 FontSubst *psub;
876 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
878 if(psub->from.charset != -1 || psub->to.charset != -1)
879 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
880 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
881 else
882 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
883 debugstr_w(psub->to.name));
885 return;
888 static LPWSTR strdupW(LPCWSTR p)
890 LPWSTR ret;
891 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
892 ret = HeapAlloc(GetProcessHeap(), 0, len);
893 memcpy(ret, p, len);
894 return ret;
897 static LPSTR strdupA(LPCSTR p)
899 LPSTR ret;
900 DWORD len = (strlen(p) + 1);
901 ret = HeapAlloc(GetProcessHeap(), 0, len);
902 memcpy(ret, p, len);
903 return ret;
906 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
907 INT from_charset)
909 FontSubst *element;
911 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
913 if(!strcmpiW(element->from.name, from_name) &&
914 (element->from.charset == from_charset ||
915 element->from.charset == -1))
916 return element;
919 return NULL;
922 #define ADD_FONT_SUBST_FORCE 1
924 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
926 FontSubst *from_exist, *to_exist;
928 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
930 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
932 list_remove(&from_exist->entry);
933 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
934 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
935 HeapFree(GetProcessHeap(), 0, from_exist);
936 from_exist = NULL;
939 if(!from_exist)
941 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
943 if(to_exist)
945 HeapFree(GetProcessHeap(), 0, subst->to.name);
946 subst->to.name = strdupW(to_exist->to.name);
949 list_add_tail(subst_list, &subst->entry);
951 return TRUE;
954 HeapFree(GetProcessHeap(), 0, subst->from.name);
955 HeapFree(GetProcessHeap(), 0, subst->to.name);
956 HeapFree(GetProcessHeap(), 0, subst);
957 return FALSE;
960 static void split_subst_info(NameCs *nc, LPSTR str)
962 CHAR *p = strrchr(str, ',');
963 DWORD len;
965 nc->charset = -1;
966 if(p && *(p+1)) {
967 nc->charset = strtol(p+1, NULL, 10);
968 *p = '\0';
970 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
971 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
972 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
975 static void LoadSubstList(void)
977 FontSubst *psub;
978 HKEY hkey;
979 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
980 LPSTR value;
981 LPVOID data;
983 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
984 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
985 &hkey) == ERROR_SUCCESS) {
987 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
988 &valuelen, &datalen, NULL, NULL);
990 valuelen++; /* returned value doesn't include room for '\0' */
991 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
992 data = HeapAlloc(GetProcessHeap(), 0, datalen);
994 dlen = datalen;
995 vlen = valuelen;
996 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
997 &dlen) == ERROR_SUCCESS) {
998 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1000 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1001 split_subst_info(&psub->from, value);
1002 split_subst_info(&psub->to, data);
1004 /* Win 2000 doesn't allow mapping between different charsets
1005 or mapping of DEFAULT_CHARSET */
1006 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1007 psub->to.charset == DEFAULT_CHARSET) {
1008 HeapFree(GetProcessHeap(), 0, psub->to.name);
1009 HeapFree(GetProcessHeap(), 0, psub->from.name);
1010 HeapFree(GetProcessHeap(), 0, psub);
1011 } else {
1012 add_font_subst(&font_subst_list, psub, 0);
1014 /* reset dlen and vlen */
1015 dlen = datalen;
1016 vlen = valuelen;
1018 HeapFree(GetProcessHeap(), 0, data);
1019 HeapFree(GetProcessHeap(), 0, value);
1020 RegCloseKey(hkey);
1024 static WCHAR *get_familyname(FT_Face ft_face)
1026 WCHAR *family = NULL;
1027 FT_SfntName name;
1028 FT_UInt num_names, name_index, i;
1030 if(FT_IS_SFNT(ft_face))
1032 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1034 for(name_index = 0; name_index < num_names; name_index++)
1036 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1038 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1039 (name.language_id == GetUserDefaultLCID()) &&
1040 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1041 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1043 /* String is not nul terminated and string_len is a byte length. */
1044 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1045 for(i = 0; i < name.string_len / 2; i++)
1047 WORD *tmp = (WORD *)&name.string[i * 2];
1048 family[i] = GET_BE_WORD(*tmp);
1050 family[i] = 0;
1052 TRACE("Got localised name %s\n", debugstr_w(family));
1053 return family;
1059 return NULL;
1063 /*****************************************************************
1064 * load_sfnt_table
1066 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1067 * of FreeType that don't export this function.
1070 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1073 FT_Error err;
1075 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1076 if(pFT_Load_Sfnt_Table)
1078 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1080 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1081 else /* Do it the hard way */
1083 TT_Face tt_face = (TT_Face) ft_face;
1084 SFNT_Interface *sfnt;
1085 if (FT_Version.major==2 && FT_Version.minor==0)
1087 /* 2.0.x */
1088 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1090 else
1092 /* A field was added in the middle of the structure in 2.1.x */
1093 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1095 err = sfnt->load_any(tt_face, table, offset, buf, len);
1097 #else
1098 else
1100 static int msg;
1101 if(!msg)
1103 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1104 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1105 "Please upgrade your freetype library.\n");
1106 msg++;
1108 err = FT_Err_Unimplemented_Feature;
1110 #endif
1111 return err;
1114 static inline int TestStyles(DWORD flags, DWORD styles)
1116 return (flags & styles) == styles;
1119 static int StyleOrdering(Face *face)
1121 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1122 return 3;
1123 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1124 return 2;
1125 if (TestStyles(face->ntmFlags, NTM_BOLD))
1126 return 1;
1127 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1128 return 0;
1130 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1131 debugstr_w(face->family->FamilyName),
1132 debugstr_w(face->StyleName),
1133 face->ntmFlags);
1135 return 9999;
1138 /* Add a style of face to a font family using an ordering of the list such
1139 that regular fonts come before bold and italic, and single styles come
1140 before compound styles. */
1141 static void AddFaceToFamily(Face *face, Family *family)
1143 struct list *entry;
1145 LIST_FOR_EACH( entry, &family->faces )
1147 Face *ent = LIST_ENTRY(entry, Face, entry);
1148 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1150 list_add_before( entry, &face->entry );
1153 #define ADDFONT_EXTERNAL_FONT 0x01
1154 #define ADDFONT_FORCE_BITMAP 0x02
1155 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1157 FT_Face ft_face;
1158 TT_OS2 *pOS2;
1159 TT_Header *pHeader = NULL;
1160 WCHAR *english_family, *localised_family, *StyleW;
1161 DWORD len;
1162 Family *family;
1163 Face *face;
1164 struct list *family_elem_ptr, *face_elem_ptr;
1165 FT_Error err;
1166 FT_Long face_index = 0, num_faces;
1167 #ifdef HAVE_FREETYPE_FTWINFNT_H
1168 FT_WinFNT_HeaderRec winfnt_header;
1169 #endif
1170 int i, bitmap_num, internal_leading;
1171 FONTSIGNATURE fs;
1173 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1174 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1176 #ifdef HAVE_CARBON_CARBON_H
1177 if(file && !fake_family)
1179 char **mac_list = expand_mac_font(file);
1180 if(mac_list)
1182 BOOL had_one = FALSE;
1183 char **cursor;
1184 for(cursor = mac_list; *cursor; cursor++)
1186 had_one = TRUE;
1187 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1188 HeapFree(GetProcessHeap(), 0, *cursor);
1190 HeapFree(GetProcessHeap(), 0, mac_list);
1191 if(had_one)
1192 return 1;
1195 #endif /* HAVE_CARBON_CARBON_H */
1197 do {
1198 char *family_name = fake_family;
1200 if (file)
1202 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1203 err = pFT_New_Face(library, file, face_index, &ft_face);
1204 } else
1206 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1207 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1210 if(err != 0) {
1211 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1212 return 0;
1215 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*/
1216 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1217 pFT_Done_Face(ft_face);
1218 return 0;
1221 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1222 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1223 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1224 pFT_Done_Face(ft_face);
1225 return 0;
1228 if(FT_IS_SFNT(ft_face))
1230 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1231 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1232 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1234 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1235 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1236 pFT_Done_Face(ft_face);
1237 return 0;
1240 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1241 we don't want to load these. */
1242 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1244 FT_ULong len = 0;
1246 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1248 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1249 pFT_Done_Face(ft_face);
1250 return 0;
1255 if(!ft_face->family_name || !ft_face->style_name) {
1256 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1257 pFT_Done_Face(ft_face);
1258 return 0;
1261 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1263 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1264 pFT_Done_Face(ft_face);
1265 return 0;
1268 if (target_family)
1270 localised_family = get_familyname(ft_face);
1271 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1273 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1274 HeapFree(GetProcessHeap(), 0, localised_family);
1275 num_faces = ft_face->num_faces;
1276 pFT_Done_Face(ft_face);
1277 continue;
1279 HeapFree(GetProcessHeap(), 0, localised_family);
1282 if(!family_name)
1283 family_name = ft_face->family_name;
1285 bitmap_num = 0;
1286 do {
1287 My_FT_Bitmap_Size *size = NULL;
1288 FT_ULong tmp_size;
1290 if(!FT_IS_SCALABLE(ft_face))
1291 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1293 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1294 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1295 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1297 localised_family = NULL;
1298 if(!fake_family) {
1299 localised_family = get_familyname(ft_face);
1300 if(localised_family && !strcmpW(localised_family, english_family)) {
1301 HeapFree(GetProcessHeap(), 0, localised_family);
1302 localised_family = NULL;
1306 family = NULL;
1307 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1308 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1309 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1310 break;
1311 family = NULL;
1313 if(!family) {
1314 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1315 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1316 list_init(&family->faces);
1317 list_add_tail(&font_list, &family->entry);
1319 if(localised_family) {
1320 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1321 subst->from.name = strdupW(english_family);
1322 subst->from.charset = -1;
1323 subst->to.name = strdupW(localised_family);
1324 subst->to.charset = -1;
1325 add_font_subst(&font_subst_list, subst, 0);
1328 HeapFree(GetProcessHeap(), 0, localised_family);
1329 HeapFree(GetProcessHeap(), 0, english_family);
1331 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1332 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1333 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1335 internal_leading = 0;
1336 memset(&fs, 0, sizeof(fs));
1338 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1339 if(pOS2) {
1340 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1341 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1342 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1343 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1344 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1345 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1346 if(pOS2->version == 0) {
1347 FT_UInt dummy;
1349 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1350 fs.fsCsb[0] |= FS_LATIN1;
1351 else
1352 fs.fsCsb[0] |= FS_SYMBOL;
1355 #ifdef HAVE_FREETYPE_FTWINFNT_H
1356 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1357 CHARSETINFO csi;
1358 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1359 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1360 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1361 fs = csi.fs;
1362 internal_leading = winfnt_header.internal_leading;
1364 #endif
1366 face_elem_ptr = list_head(&family->faces);
1367 while(face_elem_ptr) {
1368 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1369 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1370 if(!strcmpW(face->StyleName, StyleW) &&
1371 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1372 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1373 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1374 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1376 if(fake_family) {
1377 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1378 HeapFree(GetProcessHeap(), 0, StyleW);
1379 pFT_Done_Face(ft_face);
1380 return 1;
1382 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1383 TRACE("Original font is newer so skipping this one\n");
1384 HeapFree(GetProcessHeap(), 0, StyleW);
1385 pFT_Done_Face(ft_face);
1386 return 1;
1387 } else {
1388 TRACE("Replacing original with this one\n");
1389 list_remove(&face->entry);
1390 HeapFree(GetProcessHeap(), 0, face->file);
1391 HeapFree(GetProcessHeap(), 0, face->StyleName);
1392 HeapFree(GetProcessHeap(), 0, face);
1393 break;
1397 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1398 face->cached_enum_data = NULL;
1399 face->StyleName = StyleW;
1400 if (file)
1402 face->file = strdupA(file);
1403 face->font_data_ptr = NULL;
1404 face->font_data_size = 0;
1406 else
1408 face->file = NULL;
1409 face->font_data_ptr = font_data_ptr;
1410 face->font_data_size = font_data_size;
1412 face->face_index = face_index;
1413 face->ntmFlags = 0;
1414 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1415 face->ntmFlags |= NTM_ITALIC;
1416 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1417 face->ntmFlags |= NTM_BOLD;
1418 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1419 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1420 face->family = family;
1421 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1422 face->fs = fs;
1423 memset(&face->fs_links, 0, sizeof(face->fs_links));
1425 if(FT_IS_SCALABLE(ft_face)) {
1426 memset(&face->size, 0, sizeof(face->size));
1427 face->scalable = TRUE;
1428 } else {
1429 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1430 size->height, size->width, size->size >> 6,
1431 size->x_ppem >> 6, size->y_ppem >> 6);
1432 face->size.height = size->height;
1433 face->size.width = size->width;
1434 face->size.size = size->size;
1435 face->size.x_ppem = size->x_ppem;
1436 face->size.y_ppem = size->y_ppem;
1437 face->size.internal_leading = internal_leading;
1438 face->scalable = FALSE;
1441 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1442 tmp_size = 0;
1443 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1445 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1446 face->ntmFlags |= NTM_PS_OPENTYPE;
1449 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1450 face->fs.fsCsb[0], face->fs.fsCsb[1],
1451 face->fs.fsUsb[0], face->fs.fsUsb[1],
1452 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1455 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1456 for(i = 0; i < ft_face->num_charmaps; i++) {
1457 switch(ft_face->charmaps[i]->encoding) {
1458 case FT_ENCODING_UNICODE:
1459 case FT_ENCODING_APPLE_ROMAN:
1460 face->fs.fsCsb[0] |= FS_LATIN1;
1461 break;
1462 case FT_ENCODING_MS_SYMBOL:
1463 face->fs.fsCsb[0] |= FS_SYMBOL;
1464 break;
1465 default:
1466 break;
1471 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1472 have_installed_roman_font = TRUE;
1474 AddFaceToFamily(face, family);
1476 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1478 num_faces = ft_face->num_faces;
1479 pFT_Done_Face(ft_face);
1480 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1481 debugstr_w(StyleW));
1482 } while(num_faces > ++face_index);
1483 return num_faces;
1486 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1488 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1491 static void DumpFontList(void)
1493 Family *family;
1494 Face *face;
1495 struct list *family_elem_ptr, *face_elem_ptr;
1497 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1498 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1499 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1500 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1501 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1502 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1503 if(!face->scalable)
1504 TRACE(" %d", face->size.height);
1505 TRACE("\n");
1508 return;
1511 /***********************************************************
1512 * The replacement list is a way to map an entire font
1513 * family onto another family. For example adding
1515 * [HKCU\Software\Wine\Fonts\Replacements]
1516 * "Wingdings"="Winedings"
1518 * would enumerate the Winedings font both as Winedings and
1519 * Wingdings. However if a real Wingdings font is present the
1520 * replacement does not take place.
1523 static void LoadReplaceList(void)
1525 HKEY hkey;
1526 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1527 LPWSTR value;
1528 LPVOID data;
1529 Family *family;
1530 Face *face;
1531 struct list *family_elem_ptr, *face_elem_ptr;
1532 CHAR familyA[400];
1534 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1535 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1537 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1538 &valuelen, &datalen, NULL, NULL);
1540 valuelen++; /* returned value doesn't include room for '\0' */
1541 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1542 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1544 dlen = datalen;
1545 vlen = valuelen;
1546 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1547 &dlen) == ERROR_SUCCESS) {
1548 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1549 /* "NewName"="Oldname" */
1550 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1552 /* Find the old family and hence all of the font files
1553 in that family */
1554 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1555 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1556 if(!strcmpiW(family->FamilyName, data)) {
1557 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1558 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1559 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1560 debugstr_w(face->StyleName), familyA);
1561 /* Now add a new entry with the new family name */
1562 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1564 break;
1567 /* reset dlen and vlen */
1568 dlen = datalen;
1569 vlen = valuelen;
1571 HeapFree(GetProcessHeap(), 0, data);
1572 HeapFree(GetProcessHeap(), 0, value);
1573 RegCloseKey(hkey);
1577 /*************************************************************
1578 * init_system_links
1580 static BOOL init_system_links(void)
1582 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1583 'W','i','n','d','o','w','s',' ','N','T','\\',
1584 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1585 'S','y','s','t','e','m','L','i','n','k',0};
1586 HKEY hkey;
1587 BOOL ret = FALSE;
1588 DWORD type, max_val, max_data, val_len, data_len, index;
1589 WCHAR *value, *data;
1590 WCHAR *entry, *next;
1591 SYSTEM_LINKS *font_link, *system_font_link;
1592 CHILD_FONT *child_font;
1593 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1594 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1595 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1596 FONTSIGNATURE fs;
1597 Family *family;
1598 Face *face;
1599 FontSubst *psub;
1601 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1603 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1604 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1605 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1606 val_len = max_val + 1;
1607 data_len = max_data;
1608 index = 0;
1609 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1611 TRACE("%s:\n", debugstr_w(value));
1613 memset(&fs, 0, sizeof(fs));
1614 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1615 psub = get_font_subst(&font_subst_list, value, -1);
1616 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1617 list_init(&font_link->links);
1618 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1620 WCHAR *face_name;
1621 CHILD_FONT *child_font;
1623 TRACE("\t%s\n", debugstr_w(entry));
1625 next = entry + strlenW(entry) + 1;
1627 face_name = strchrW(entry, ',');
1628 if(face_name)
1630 *face_name++ = 0;
1631 while(isspaceW(*face_name))
1632 face_name++;
1634 psub = get_font_subst(&font_subst_list, face_name, -1);
1635 if(psub)
1636 face_name = psub->to.name;
1638 face = find_face_from_filename(entry, face_name);
1639 if(!face)
1641 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1642 continue;
1645 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1646 child_font->face = face;
1647 child_font->font = NULL;
1648 fs.fsCsb[0] |= face->fs.fsCsb[0];
1649 fs.fsCsb[1] |= face->fs.fsCsb[1];
1650 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1651 list_add_tail(&font_link->links, &child_font->entry);
1653 family = find_family_from_name(font_link->font_name);
1654 if(family)
1656 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1658 face->fs_links = fs;
1661 list_add_tail(&system_links, &font_link->entry);
1662 val_len = max_val + 1;
1663 data_len = max_data;
1666 HeapFree(GetProcessHeap(), 0, value);
1667 HeapFree(GetProcessHeap(), 0, data);
1668 RegCloseKey(hkey);
1671 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1672 that Tahoma has */
1674 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1675 system_font_link->font_name = strdupW(System);
1676 list_init(&system_font_link->links);
1678 face = find_face_from_filename(tahoma_ttf, Tahoma);
1679 if(face)
1681 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1682 child_font->face = face;
1683 child_font->font = NULL;
1684 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1685 list_add_tail(&system_font_link->links, &child_font->entry);
1687 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1689 if(!strcmpiW(font_link->font_name, Tahoma))
1691 CHILD_FONT *font_link_entry;
1692 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1694 CHILD_FONT *new_child;
1695 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1696 new_child->face = font_link_entry->face;
1697 new_child->font = NULL;
1698 list_add_tail(&system_font_link->links, &new_child->entry);
1700 break;
1703 list_add_tail(&system_links, &system_font_link->entry);
1704 return ret;
1707 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1709 DIR *dir;
1710 struct dirent *dent;
1711 char path[MAX_PATH];
1713 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1715 dir = opendir(dirname);
1716 if(!dir) {
1717 WARN("Can't open directory %s\n", debugstr_a(dirname));
1718 return FALSE;
1720 while((dent = readdir(dir)) != NULL) {
1721 struct stat statbuf;
1723 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1724 continue;
1726 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1728 sprintf(path, "%s/%s", dirname, dent->d_name);
1730 if(stat(path, &statbuf) == -1)
1732 WARN("Can't stat %s\n", debugstr_a(path));
1733 continue;
1735 if(S_ISDIR(statbuf.st_mode))
1736 ReadFontDir(path, external_fonts);
1737 else
1738 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1740 closedir(dir);
1741 return TRUE;
1744 static void load_fontconfig_fonts(void)
1746 #ifdef SONAME_LIBFONTCONFIG
1747 void *fc_handle = NULL;
1748 FcConfig *config;
1749 FcPattern *pat;
1750 FcObjectSet *os;
1751 FcFontSet *fontset;
1752 int i, len;
1753 char *file;
1754 const char *ext;
1756 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1757 if(!fc_handle) {
1758 TRACE("Wine cannot find the fontconfig library (%s).\n",
1759 SONAME_LIBFONTCONFIG);
1760 return;
1762 #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;}
1763 LOAD_FUNCPTR(FcConfigGetCurrent);
1764 LOAD_FUNCPTR(FcFontList);
1765 LOAD_FUNCPTR(FcFontSetDestroy);
1766 LOAD_FUNCPTR(FcInit);
1767 LOAD_FUNCPTR(FcObjectSetAdd);
1768 LOAD_FUNCPTR(FcObjectSetCreate);
1769 LOAD_FUNCPTR(FcObjectSetDestroy);
1770 LOAD_FUNCPTR(FcPatternCreate);
1771 LOAD_FUNCPTR(FcPatternDestroy);
1772 LOAD_FUNCPTR(FcPatternGetBool);
1773 LOAD_FUNCPTR(FcPatternGetString);
1774 #undef LOAD_FUNCPTR
1776 if(!pFcInit()) return;
1778 config = pFcConfigGetCurrent();
1779 pat = pFcPatternCreate();
1780 os = pFcObjectSetCreate();
1781 pFcObjectSetAdd(os, FC_FILE);
1782 pFcObjectSetAdd(os, FC_SCALABLE);
1783 fontset = pFcFontList(config, pat, os);
1784 if(!fontset) return;
1785 for(i = 0; i < fontset->nfont; i++) {
1786 FcBool scalable;
1788 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1789 continue;
1790 TRACE("fontconfig: %s\n", file);
1792 /* We're just interested in OT/TT fonts for now, so this hack just
1793 picks up the scalable fonts without extensions .pf[ab] to save time
1794 loading every other font */
1796 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1798 TRACE("not scalable\n");
1799 continue;
1802 len = strlen( file );
1803 if(len < 4) continue;
1804 ext = &file[ len - 3 ];
1805 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1806 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1808 pFcFontSetDestroy(fontset);
1809 pFcObjectSetDestroy(os);
1810 pFcPatternDestroy(pat);
1811 sym_not_found:
1812 #endif
1813 return;
1816 static BOOL load_font_from_data_dir(LPCWSTR file)
1818 BOOL ret = FALSE;
1819 const char *data_dir = wine_get_data_dir();
1821 if (!data_dir) data_dir = wine_get_build_dir();
1823 if (data_dir)
1825 INT len;
1826 char *unix_name;
1828 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1830 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1832 strcpy(unix_name, data_dir);
1833 strcat(unix_name, "/fonts/");
1835 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1837 EnterCriticalSection( &freetype_cs );
1838 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1839 LeaveCriticalSection( &freetype_cs );
1840 HeapFree(GetProcessHeap(), 0, unix_name);
1842 return ret;
1845 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1847 static const WCHAR slashW[] = {'\\','\0'};
1848 BOOL ret = FALSE;
1849 WCHAR windowsdir[MAX_PATH];
1850 char *unixname;
1852 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1853 strcatW(windowsdir, fontsW);
1854 strcatW(windowsdir, slashW);
1855 strcatW(windowsdir, file);
1856 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1857 EnterCriticalSection( &freetype_cs );
1858 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1859 LeaveCriticalSection( &freetype_cs );
1860 HeapFree(GetProcessHeap(), 0, unixname);
1862 return ret;
1865 static void load_system_fonts(void)
1867 HKEY hkey;
1868 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1869 const WCHAR * const *value;
1870 DWORD dlen, type;
1871 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1872 char *unixname;
1874 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1875 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1876 strcatW(windowsdir, fontsW);
1877 for(value = SystemFontValues; *value; value++) {
1878 dlen = sizeof(data);
1879 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1880 type == REG_SZ) {
1881 BOOL added = FALSE;
1883 sprintfW(pathW, fmtW, windowsdir, data);
1884 if((unixname = wine_get_unix_file_name(pathW))) {
1885 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1886 HeapFree(GetProcessHeap(), 0, unixname);
1888 if (!added)
1889 load_font_from_data_dir(data);
1892 RegCloseKey(hkey);
1896 /*************************************************************
1898 * This adds registry entries for any externally loaded fonts
1899 * (fonts from fontconfig or FontDirs). It also deletes entries
1900 * of no longer existing fonts.
1903 static void update_reg_entries(void)
1905 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1906 LPWSTR valueW;
1907 DWORD len, len_fam;
1908 Family *family;
1909 Face *face;
1910 struct list *family_elem_ptr, *face_elem_ptr;
1911 WCHAR *file;
1912 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1913 static const WCHAR spaceW[] = {' ', '\0'};
1914 char *path;
1916 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1917 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1918 ERR("Can't create Windows font reg key\n");
1919 goto end;
1922 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1923 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1924 ERR("Can't create Windows font reg key\n");
1925 goto end;
1928 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1929 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1930 ERR("Can't create external font reg key\n");
1931 goto end;
1934 /* enumerate the fonts and add external ones to the two keys */
1936 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1937 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1938 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1939 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1940 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1941 if(!face->external) continue;
1942 len = len_fam;
1943 if (!(face->ntmFlags & NTM_REGULAR))
1944 len = len_fam + strlenW(face->StyleName) + 1;
1945 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1946 strcpyW(valueW, family->FamilyName);
1947 if(len != len_fam) {
1948 strcatW(valueW, spaceW);
1949 strcatW(valueW, face->StyleName);
1951 strcatW(valueW, TrueType);
1953 file = wine_get_dos_file_name(face->file);
1954 if(file)
1955 len = strlenW(file) + 1;
1956 else
1958 if((path = strrchr(face->file, '/')) == NULL)
1959 path = face->file;
1960 else
1961 path++;
1962 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1964 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1965 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1967 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1968 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1969 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1971 HeapFree(GetProcessHeap(), 0, file);
1972 HeapFree(GetProcessHeap(), 0, valueW);
1975 end:
1976 if(external_key) RegCloseKey(external_key);
1977 if(win9x_key) RegCloseKey(win9x_key);
1978 if(winnt_key) RegCloseKey(winnt_key);
1979 return;
1982 static void delete_external_font_keys(void)
1984 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1985 DWORD dlen, vlen, datalen, valuelen, i, type;
1986 LPWSTR valueW;
1987 LPVOID data;
1989 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1990 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1991 ERR("Can't create Windows font reg key\n");
1992 goto end;
1995 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1996 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1997 ERR("Can't create Windows font reg key\n");
1998 goto end;
2001 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2002 ERR("Can't create external font reg key\n");
2003 goto end;
2006 /* Delete all external fonts added last time */
2008 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2009 &valuelen, &datalen, NULL, NULL);
2010 valuelen++; /* returned value doesn't include room for '\0' */
2011 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2012 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2014 dlen = datalen * sizeof(WCHAR);
2015 vlen = valuelen;
2016 i = 0;
2017 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2018 &dlen) == ERROR_SUCCESS) {
2020 RegDeleteValueW(winnt_key, valueW);
2021 RegDeleteValueW(win9x_key, valueW);
2022 /* reset dlen and vlen */
2023 dlen = datalen;
2024 vlen = valuelen;
2026 HeapFree(GetProcessHeap(), 0, data);
2027 HeapFree(GetProcessHeap(), 0, valueW);
2029 /* Delete the old external fonts key */
2030 RegCloseKey(external_key);
2031 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2033 end:
2034 if(win9x_key) RegCloseKey(win9x_key);
2035 if(winnt_key) RegCloseKey(winnt_key);
2038 /*************************************************************
2039 * WineEngAddFontResourceEx
2042 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2044 INT ret = 0;
2045 if (ft_handle) /* do it only if we have freetype up and running */
2047 char *unixname;
2049 if(flags)
2050 FIXME("Ignoring flags %x\n", flags);
2052 if((unixname = wine_get_unix_file_name(file)))
2054 EnterCriticalSection( &freetype_cs );
2055 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2056 LeaveCriticalSection( &freetype_cs );
2057 HeapFree(GetProcessHeap(), 0, unixname);
2059 if (!ret && !strchrW(file, '\\')) {
2060 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2061 ret = load_font_from_winfonts_dir(file);
2062 if (!ret) {
2063 /* Try in datadir/fonts (or builddir/fonts),
2064 * needed for Magic the Gathering Online
2066 ret = load_font_from_data_dir(file);
2070 return ret;
2073 /*************************************************************
2074 * WineEngAddFontMemResourceEx
2077 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2079 if (ft_handle) /* do it only if we have freetype up and running */
2081 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2083 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2084 memcpy(pFontCopy, pbFont, cbFont);
2086 EnterCriticalSection( &freetype_cs );
2087 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2088 LeaveCriticalSection( &freetype_cs );
2090 if (*pcFonts == 0)
2092 TRACE("AddFontToList failed\n");
2093 HeapFree(GetProcessHeap(), 0, pFontCopy);
2094 return NULL;
2096 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2097 * For now return something unique but quite random
2099 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2100 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2103 *pcFonts = 0;
2104 return 0;
2107 /*************************************************************
2108 * WineEngRemoveFontResourceEx
2111 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2113 FIXME(":stub\n");
2114 return TRUE;
2117 static const struct nls_update_font_list
2119 UINT ansi_cp, oem_cp;
2120 const char *oem, *fixed, *system;
2121 const char *courier, *serif, *small, *sserif;
2122 /* these are for font substitutes */
2123 const char *shelldlg, *tmsrmn;
2124 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2125 *helv_0, *tmsrmn_0;
2126 const struct subst
2128 const char *from, *to;
2129 } arial_0, courier_new_0, times_new_roman_0;
2130 } nls_update_font_list[] =
2132 /* Latin 1 (United States) */
2133 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2134 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2135 "Tahoma","Times New Roman",
2136 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2137 { 0 }, { 0 }, { 0 }
2139 /* Latin 1 (Multilingual) */
2140 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2141 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2142 "Tahoma","Times New Roman", /* FIXME unverified */
2143 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2144 { 0 }, { 0 }, { 0 }
2146 /* Eastern Europe */
2147 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2148 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2149 "Tahoma","Times New Roman", /* FIXME unverified */
2150 "Fixedsys,238", "System,238",
2151 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2152 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2153 { "Arial CE,0", "Arial,238" },
2154 { "Courier New CE,0", "Courier New,238" },
2155 { "Times New Roman CE,0", "Times New Roman,238" }
2157 /* Cyrillic */
2158 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2159 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2160 "Tahoma","Times New Roman", /* FIXME unverified */
2161 "Fixedsys,204", "System,204",
2162 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2163 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2164 { "Arial Cyr,0", "Arial,204" },
2165 { "Courier New Cyr,0", "Courier New,204" },
2166 { "Times New Roman Cyr,0", "Times New Roman,204" }
2168 /* Greek */
2169 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2170 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2171 "Tahoma","Times New Roman", /* FIXME unverified */
2172 "Fixedsys,161", "System,161",
2173 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2174 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2175 { "Arial Greek,0", "Arial,161" },
2176 { "Courier New Greek,0", "Courier New,161" },
2177 { "Times New Roman Greek,0", "Times New Roman,161" }
2179 /* Turkish */
2180 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2181 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2182 "Tahoma","Times New Roman", /* FIXME unverified */
2183 "Fixedsys,162", "System,162",
2184 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2185 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2186 { "Arial Tur,0", "Arial,162" },
2187 { "Courier New Tur,0", "Courier New,162" },
2188 { "Times New Roman Tur,0", "Times New Roman,162" }
2190 /* Hebrew */
2191 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2192 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2193 "Tahoma","Times New Roman", /* FIXME unverified */
2194 "Fixedsys,177", "System,177",
2195 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2196 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2197 { 0 }, { 0 }, { 0 }
2199 /* Arabic */
2200 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2201 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2202 "Tahoma","Times New Roman", /* FIXME unverified */
2203 "Fixedsys,178", "System,178",
2204 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2205 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2206 { 0 }, { 0 }, { 0 }
2208 /* Baltic */
2209 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2210 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2211 "Tahoma","Times New Roman", /* FIXME unverified */
2212 "Fixedsys,186", "System,186",
2213 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2214 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2215 { "Arial Baltic,0", "Arial,186" },
2216 { "Courier New Baltic,0", "Courier New,186" },
2217 { "Times New Roman Baltic,0", "Times New Roman,186" }
2219 /* Vietnamese */
2220 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2221 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2222 "Tahoma","Times New Roman", /* FIXME unverified */
2223 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2224 { 0 }, { 0 }, { 0 }
2226 /* Thai */
2227 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2228 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2229 "Tahoma","Times New Roman", /* FIXME unverified */
2230 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2231 { 0 }, { 0 }, { 0 }
2233 /* Japanese */
2234 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2235 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2236 "MS UI Gothic","MS Serif",
2237 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2238 { 0 }, { 0 }, { 0 }
2240 /* Chinese Simplified */
2241 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2242 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2243 "Tahoma", "Times New Roman", /* FIXME unverified */
2244 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2245 { 0 }, { 0 }, { 0 }
2247 /* Korean */
2248 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2249 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2250 "Gulim", "Batang",
2251 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2252 { 0 }, { 0 }, { 0 }
2254 /* Chinese Traditional */
2255 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2256 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2257 "PMingLiU", "MingLiU",
2258 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2259 { 0 }, { 0 }, { 0 }
2263 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2265 return ( ansi_cp == 932 /* CP932 for Japanese */
2266 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2267 || ansi_cp == 949 /* CP949 for Korean */
2268 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2271 static inline HKEY create_fonts_NT_registry_key(void)
2273 HKEY hkey = 0;
2275 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2276 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2277 return hkey;
2280 static inline HKEY create_fonts_9x_registry_key(void)
2282 HKEY hkey = 0;
2284 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2285 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2286 return hkey;
2289 static inline HKEY create_config_fonts_registry_key(void)
2291 HKEY hkey = 0;
2293 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2294 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2295 return hkey;
2298 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2300 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2301 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2302 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2303 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2306 static void set_value_key(HKEY hkey, const char *name, const char *value)
2308 if (value)
2309 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2310 else if (name)
2311 RegDeleteValueA(hkey, name);
2314 static void update_font_info(void)
2316 char buf[40], cpbuf[40];
2317 DWORD len, type;
2318 HKEY hkey = 0;
2319 UINT i, ansi_cp = 0, oem_cp = 0;
2320 BOOL done = FALSE;
2322 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2323 return;
2325 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2326 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2327 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2328 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2329 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2331 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2332 if (is_dbcs_ansi_cp(ansi_cp))
2333 use_default_fallback = TRUE;
2335 len = sizeof(buf);
2336 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2338 if (!strcmp( buf, cpbuf )) /* already set correctly */
2340 RegCloseKey(hkey);
2341 return;
2343 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2345 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2347 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2348 RegCloseKey(hkey);
2350 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2352 HKEY hkey;
2354 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2355 nls_update_font_list[i].oem_cp == oem_cp)
2357 hkey = create_config_fonts_registry_key();
2358 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2359 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2360 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2361 RegCloseKey(hkey);
2363 hkey = create_fonts_NT_registry_key();
2364 add_font_list(hkey, &nls_update_font_list[i]);
2365 RegCloseKey(hkey);
2367 hkey = create_fonts_9x_registry_key();
2368 add_font_list(hkey, &nls_update_font_list[i]);
2369 RegCloseKey(hkey);
2371 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2373 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2374 strlen(nls_update_font_list[i].shelldlg)+1);
2375 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2376 strlen(nls_update_font_list[i].tmsrmn)+1);
2378 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2379 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2380 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2381 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2382 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2383 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2384 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2385 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2387 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2388 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2389 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2391 RegCloseKey(hkey);
2393 done = TRUE;
2395 else
2397 /* Delete the FontSubstitutes from other locales */
2398 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2400 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2401 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2402 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2403 RegCloseKey(hkey);
2407 if (!done)
2408 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2412 static BOOL init_freetype(void)
2414 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2415 if(!ft_handle) {
2416 WINE_MESSAGE(
2417 "Wine cannot find the FreeType font library. To enable Wine to\n"
2418 "use TrueType fonts please install a version of FreeType greater than\n"
2419 "or equal to 2.0.5.\n"
2420 "http://www.freetype.org\n");
2421 return FALSE;
2424 #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;}
2426 LOAD_FUNCPTR(FT_Vector_Unit)
2427 LOAD_FUNCPTR(FT_Done_Face)
2428 LOAD_FUNCPTR(FT_Get_Char_Index)
2429 LOAD_FUNCPTR(FT_Get_Module)
2430 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2431 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2432 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2433 LOAD_FUNCPTR(FT_Init_FreeType)
2434 LOAD_FUNCPTR(FT_Load_Glyph)
2435 LOAD_FUNCPTR(FT_Matrix_Multiply)
2436 LOAD_FUNCPTR(FT_MulFix)
2437 LOAD_FUNCPTR(FT_New_Face)
2438 LOAD_FUNCPTR(FT_New_Memory_Face)
2439 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2440 LOAD_FUNCPTR(FT_Outline_Transform)
2441 LOAD_FUNCPTR(FT_Outline_Translate)
2442 LOAD_FUNCPTR(FT_Select_Charmap)
2443 LOAD_FUNCPTR(FT_Set_Charmap)
2444 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2445 LOAD_FUNCPTR(FT_Vector_Transform)
2447 #undef LOAD_FUNCPTR
2448 /* Don't warn if these ones are missing */
2449 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2450 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2451 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2452 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2453 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2454 #ifdef HAVE_FREETYPE_FTWINFNT_H
2455 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2456 #endif
2457 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2458 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2459 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2460 <= 2.0.3 has FT_Sqrt64 */
2461 goto sym_not_found;
2464 if(pFT_Init_FreeType(&library) != 0) {
2465 ERR("Can't init FreeType library\n");
2466 wine_dlclose(ft_handle, NULL, 0);
2467 ft_handle = NULL;
2468 return FALSE;
2470 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2471 if (pFT_Library_Version)
2472 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2474 if (FT_Version.major<=0)
2476 FT_Version.major=2;
2477 FT_Version.minor=0;
2478 FT_Version.patch=5;
2480 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2481 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2482 ((FT_Version.minor << 8) & 0x00ff00) |
2483 ((FT_Version.patch ) & 0x0000ff);
2485 return TRUE;
2487 sym_not_found:
2488 WINE_MESSAGE(
2489 "Wine cannot find certain functions that it needs inside the FreeType\n"
2490 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2491 "FreeType to at least version 2.0.5.\n"
2492 "http://www.freetype.org\n");
2493 wine_dlclose(ft_handle, NULL, 0);
2494 ft_handle = NULL;
2495 return FALSE;
2498 /*************************************************************
2499 * WineEngInit
2501 * Initialize FreeType library and create a list of available faces
2503 BOOL WineEngInit(void)
2505 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2506 static const WCHAR pathW[] = {'P','a','t','h',0};
2507 HKEY hkey;
2508 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2509 LPVOID data;
2510 WCHAR windowsdir[MAX_PATH];
2511 char *unixname;
2512 HANDLE font_mutex;
2513 const char *data_dir;
2515 TRACE("\n");
2517 /* update locale dependent font info in registry */
2518 update_font_info();
2520 if(!init_freetype()) return FALSE;
2522 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2523 ERR("Failed to create font mutex\n");
2524 return FALSE;
2526 WaitForSingleObject(font_mutex, INFINITE);
2528 delete_external_font_keys();
2530 /* load the system bitmap fonts */
2531 load_system_fonts();
2533 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2534 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2535 strcatW(windowsdir, fontsW);
2536 if((unixname = wine_get_unix_file_name(windowsdir)))
2538 ReadFontDir(unixname, FALSE);
2539 HeapFree(GetProcessHeap(), 0, unixname);
2542 /* load the system truetype fonts */
2543 data_dir = wine_get_data_dir();
2544 if (!data_dir) data_dir = wine_get_build_dir();
2545 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2546 strcpy(unixname, data_dir);
2547 strcat(unixname, "/fonts/");
2548 ReadFontDir(unixname, TRUE);
2549 HeapFree(GetProcessHeap(), 0, unixname);
2552 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2553 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2554 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2555 will skip these. */
2556 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2557 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2558 &hkey) == ERROR_SUCCESS) {
2559 LPWSTR valueW;
2560 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2561 &valuelen, &datalen, NULL, NULL);
2563 valuelen++; /* returned value doesn't include room for '\0' */
2564 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2565 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2566 if (valueW && data)
2568 dlen = datalen * sizeof(WCHAR);
2569 vlen = valuelen;
2570 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2571 &dlen) == ERROR_SUCCESS) {
2572 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2574 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2576 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2577 HeapFree(GetProcessHeap(), 0, unixname);
2580 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2582 WCHAR pathW[MAX_PATH];
2583 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2584 BOOL added = FALSE;
2586 sprintfW(pathW, fmtW, windowsdir, data);
2587 if((unixname = wine_get_unix_file_name(pathW)))
2589 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2590 HeapFree(GetProcessHeap(), 0, unixname);
2592 if (!added)
2593 load_font_from_data_dir(data);
2595 /* reset dlen and vlen */
2596 dlen = datalen;
2597 vlen = valuelen;
2600 HeapFree(GetProcessHeap(), 0, data);
2601 HeapFree(GetProcessHeap(), 0, valueW);
2602 RegCloseKey(hkey);
2605 load_fontconfig_fonts();
2607 /* then look in any directories that we've specified in the config file */
2608 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2609 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2611 DWORD len;
2612 LPWSTR valueW;
2613 LPSTR valueA, ptr;
2615 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2617 len += sizeof(WCHAR);
2618 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2619 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2621 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2622 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2623 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2624 TRACE( "got font path %s\n", debugstr_a(valueA) );
2625 ptr = valueA;
2626 while (ptr)
2628 LPSTR next = strchr( ptr, ':' );
2629 if (next) *next++ = 0;
2630 ReadFontDir( ptr, TRUE );
2631 ptr = next;
2633 HeapFree( GetProcessHeap(), 0, valueA );
2635 HeapFree( GetProcessHeap(), 0, valueW );
2637 RegCloseKey(hkey);
2640 DumpFontList();
2641 LoadSubstList();
2642 DumpSubstList();
2643 LoadReplaceList();
2644 update_reg_entries();
2646 init_system_links();
2648 ReleaseMutex(font_mutex);
2649 return TRUE;
2653 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2655 TT_OS2 *pOS2;
2656 TT_HoriHeader *pHori;
2658 LONG ppem;
2660 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2661 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2663 if(height == 0) height = 16;
2665 /* Calc. height of EM square:
2667 * For +ve lfHeight we have
2668 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2669 * Re-arranging gives:
2670 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2672 * For -ve lfHeight we have
2673 * |lfHeight| = ppem
2674 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2675 * with il = winAscent + winDescent - units_per_em]
2679 if(height > 0) {
2680 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2681 ppem = MulDiv(ft_face->units_per_EM, height,
2682 pHori->Ascender - pHori->Descender);
2683 else
2684 ppem = MulDiv(ft_face->units_per_EM, height,
2685 pOS2->usWinAscent + pOS2->usWinDescent);
2687 else
2688 ppem = -height;
2690 return ppem;
2693 static struct font_mapping *map_font_file( const char *name )
2695 struct font_mapping *mapping;
2696 struct stat st;
2697 int fd;
2699 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2700 if (fstat( fd, &st ) == -1) goto error;
2702 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2704 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2706 mapping->refcount++;
2707 close( fd );
2708 return mapping;
2711 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2712 goto error;
2714 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2715 close( fd );
2717 if (mapping->data == MAP_FAILED)
2719 HeapFree( GetProcessHeap(), 0, mapping );
2720 return NULL;
2722 mapping->refcount = 1;
2723 mapping->dev = st.st_dev;
2724 mapping->ino = st.st_ino;
2725 mapping->size = st.st_size;
2726 list_add_tail( &mappings_list, &mapping->entry );
2727 return mapping;
2729 error:
2730 close( fd );
2731 return NULL;
2734 static void unmap_font_file( struct font_mapping *mapping )
2736 if (!--mapping->refcount)
2738 list_remove( &mapping->entry );
2739 munmap( mapping->data, mapping->size );
2740 HeapFree( GetProcessHeap(), 0, mapping );
2744 static LONG load_VDMX(GdiFont*, LONG);
2746 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2748 FT_Error err;
2749 FT_Face ft_face;
2750 void *data_ptr;
2751 DWORD data_size;
2753 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2755 if (face->file)
2757 if (!(font->mapping = map_font_file( face->file )))
2759 WARN("failed to map %s\n", debugstr_a(face->file));
2760 return 0;
2762 data_ptr = font->mapping->data;
2763 data_size = font->mapping->size;
2765 else
2767 data_ptr = face->font_data_ptr;
2768 data_size = face->font_data_size;
2771 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2772 if(err) {
2773 ERR("FT_New_Face rets %d\n", err);
2774 return 0;
2777 /* set it here, as load_VDMX needs it */
2778 font->ft_face = ft_face;
2780 if(FT_IS_SCALABLE(ft_face)) {
2781 /* load the VDMX table if we have one */
2782 font->ppem = load_VDMX(font, height);
2783 if(font->ppem == 0)
2784 font->ppem = calc_ppem_for_height(ft_face, height);
2785 TRACE("height %d => ppem %d\n", height, font->ppem);
2787 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2788 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2789 } else {
2790 font->ppem = height;
2791 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2792 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2794 return ft_face;
2798 static int get_nearest_charset(Face *face, int *cp)
2800 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2801 a single face with the requested charset. The idea is to check if
2802 the selected font supports the current ANSI codepage, if it does
2803 return the corresponding charset, else return the first charset */
2805 CHARSETINFO csi;
2806 int acp = GetACP(), i;
2807 DWORD fs0;
2809 *cp = acp;
2810 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2811 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2812 return csi.ciCharset;
2814 for(i = 0; i < 32; i++) {
2815 fs0 = 1L << i;
2816 if(face->fs.fsCsb[0] & fs0) {
2817 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2818 *cp = csi.ciACP;
2819 return csi.ciCharset;
2821 else
2822 FIXME("TCI failing on %x\n", fs0);
2826 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2827 face->fs.fsCsb[0], face->file);
2828 *cp = acp;
2829 return DEFAULT_CHARSET;
2832 static GdiFont *alloc_font(void)
2834 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2835 ret->gmsize = 1;
2836 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2837 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2838 ret->potm = NULL;
2839 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2840 ret->total_kern_pairs = (DWORD)-1;
2841 ret->kern_pairs = NULL;
2842 list_init(&ret->hfontlist);
2843 list_init(&ret->child_fonts);
2844 return ret;
2847 static void free_font(GdiFont *font)
2849 struct list *cursor, *cursor2;
2850 int i;
2852 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2854 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2855 struct list *first_hfont;
2856 HFONTLIST *hfontlist;
2857 list_remove(cursor);
2858 if(child->font)
2860 first_hfont = list_head(&child->font->hfontlist);
2861 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2862 DeleteObject(hfontlist->hfont);
2863 HeapFree(GetProcessHeap(), 0, hfontlist);
2864 free_font(child->font);
2866 HeapFree(GetProcessHeap(), 0, child);
2869 if (font->ft_face) pFT_Done_Face(font->ft_face);
2870 if (font->mapping) unmap_font_file( font->mapping );
2871 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2872 HeapFree(GetProcessHeap(), 0, font->potm);
2873 HeapFree(GetProcessHeap(), 0, font->name);
2874 for (i = 0; i < font->gmsize; i++)
2875 HeapFree(GetProcessHeap(),0,font->gm[i]);
2876 HeapFree(GetProcessHeap(), 0, font->gm);
2877 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2878 HeapFree(GetProcessHeap(), 0, font);
2882 /*************************************************************
2883 * load_VDMX
2885 * load the vdmx entry for the specified height
2888 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2889 ( ( (FT_ULong)_x4 << 24 ) | \
2890 ( (FT_ULong)_x3 << 16 ) | \
2891 ( (FT_ULong)_x2 << 8 ) | \
2892 (FT_ULong)_x1 )
2894 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2896 typedef struct {
2897 BYTE bCharSet;
2898 BYTE xRatio;
2899 BYTE yStartRatio;
2900 BYTE yEndRatio;
2901 } Ratios;
2903 typedef struct {
2904 WORD recs;
2905 BYTE startsz;
2906 BYTE endsz;
2907 } VDMX_group;
2909 static LONG load_VDMX(GdiFont *font, LONG height)
2911 WORD hdr[3], tmp;
2912 VDMX_group group;
2913 BYTE devXRatio, devYRatio;
2914 USHORT numRecs, numRatios;
2915 DWORD result, offset = -1;
2916 LONG ppem = 0;
2917 int i;
2919 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2921 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2922 return ppem;
2924 /* FIXME: need the real device aspect ratio */
2925 devXRatio = 1;
2926 devYRatio = 1;
2928 numRecs = GET_BE_WORD(hdr[1]);
2929 numRatios = GET_BE_WORD(hdr[2]);
2931 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2932 for(i = 0; i < numRatios; i++) {
2933 Ratios ratio;
2935 offset = (3 * 2) + (i * sizeof(Ratios));
2936 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2937 offset = -1;
2939 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2941 if((ratio.xRatio == 0 &&
2942 ratio.yStartRatio == 0 &&
2943 ratio.yEndRatio == 0) ||
2944 (devXRatio == ratio.xRatio &&
2945 devYRatio >= ratio.yStartRatio &&
2946 devYRatio <= ratio.yEndRatio))
2948 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2949 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2950 offset = GET_BE_WORD(tmp);
2951 break;
2955 if(offset == -1) {
2956 FIXME("No suitable ratio found\n");
2957 return ppem;
2960 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2961 USHORT recs;
2962 BYTE startsz, endsz;
2963 WORD *vTable;
2965 recs = GET_BE_WORD(group.recs);
2966 startsz = group.startsz;
2967 endsz = group.endsz;
2969 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2971 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2972 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2973 if(result == GDI_ERROR) {
2974 FIXME("Failed to retrieve vTable\n");
2975 goto end;
2978 if(height > 0) {
2979 for(i = 0; i < recs; i++) {
2980 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2981 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2982 ppem = GET_BE_WORD(vTable[i * 3]);
2984 if(yMax + -yMin == height) {
2985 font->yMax = yMax;
2986 font->yMin = yMin;
2987 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2988 break;
2990 if(yMax + -yMin > height) {
2991 if(--i < 0) {
2992 ppem = 0;
2993 goto end; /* failed */
2995 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2996 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2997 ppem = GET_BE_WORD(vTable[i * 3]);
2998 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2999 break;
3002 if(!font->yMax) {
3003 ppem = 0;
3004 TRACE("ppem not found for height %d\n", height);
3006 } else {
3007 ppem = -height;
3008 if(ppem < startsz || ppem > endsz)
3009 goto end;
3011 for(i = 0; i < recs; i++) {
3012 USHORT yPelHeight;
3013 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3015 if(yPelHeight > ppem)
3016 break; /* failed */
3018 if(yPelHeight == ppem) {
3019 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3020 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3021 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3022 break;
3026 end:
3027 HeapFree(GetProcessHeap(), 0, vTable);
3030 return ppem;
3033 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3035 if(font->font_desc.hash != fd->hash) return TRUE;
3036 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3037 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3038 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3039 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3042 static void calc_hash(FONT_DESC *pfd)
3044 DWORD hash = 0, *ptr, two_chars;
3045 WORD *pwc;
3046 unsigned int i;
3048 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3049 hash ^= *ptr;
3050 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3051 hash ^= *ptr;
3052 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3053 two_chars = *ptr;
3054 pwc = (WCHAR *)&two_chars;
3055 if(!*pwc) break;
3056 *pwc = toupperW(*pwc);
3057 pwc++;
3058 *pwc = toupperW(*pwc);
3059 hash ^= two_chars;
3060 if(!*pwc) break;
3062 hash ^= !pfd->can_use_bitmap;
3063 pfd->hash = hash;
3064 return;
3067 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3069 GdiFont *ret;
3070 FONT_DESC fd;
3071 HFONTLIST *hflist;
3072 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3074 fd.lf = *plf;
3075 fd.matrix = *pmat;
3076 fd.can_use_bitmap = can_use_bitmap;
3077 calc_hash(&fd);
3079 /* try the in-use list */
3080 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3081 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3082 if(!fontcmp(ret, &fd)) {
3083 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3084 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3085 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3086 if(hflist->hfont == hfont)
3087 return ret;
3089 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3090 hflist->hfont = hfont;
3091 list_add_head(&ret->hfontlist, &hflist->entry);
3092 return ret;
3096 /* then the unused list */
3097 font_elem_ptr = list_head(&unused_gdi_font_list);
3098 while(font_elem_ptr) {
3099 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3100 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3101 if(!fontcmp(ret, &fd)) {
3102 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3103 assert(list_empty(&ret->hfontlist));
3104 TRACE("Found %p in unused list\n", ret);
3105 list_remove(&ret->entry);
3106 list_add_head(&gdi_font_list, &ret->entry);
3107 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3108 hflist->hfont = hfont;
3109 list_add_head(&ret->hfontlist, &hflist->entry);
3110 return ret;
3113 return NULL;
3117 /*************************************************************
3118 * create_child_font_list
3120 static BOOL create_child_font_list(GdiFont *font)
3122 BOOL ret = FALSE;
3123 SYSTEM_LINKS *font_link;
3124 CHILD_FONT *font_link_entry, *new_child;
3126 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3128 if(!strcmpW(font_link->font_name, font->name))
3130 TRACE("found entry in system list\n");
3131 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3133 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3134 new_child->face = font_link_entry->face;
3135 new_child->font = NULL;
3136 list_add_tail(&font->child_fonts, &new_child->entry);
3137 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3139 ret = TRUE;
3140 break;
3144 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3145 * Sans Serif. This is how asian windows get default fallbacks for fonts
3147 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3148 font->charset != OEM_CHARSET &&
3149 strcmpW(font->name,szDefaultFallbackLink) != 0)
3150 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3152 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3154 TRACE("found entry in default fallback list\n");
3155 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3157 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3158 new_child->face = font_link_entry->face;
3159 new_child->font = NULL;
3160 list_add_tail(&font->child_fonts, &new_child->entry);
3161 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3163 ret = TRUE;
3164 break;
3168 return ret;
3171 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3173 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3175 if (pFT_Set_Charmap)
3177 FT_Int i;
3178 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3180 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3182 for (i = 0; i < ft_face->num_charmaps; i++)
3184 if (ft_face->charmaps[i]->encoding == encoding)
3186 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3187 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3189 switch (ft_face->charmaps[i]->platform_id)
3191 default:
3192 cmap_def = ft_face->charmaps[i];
3193 break;
3194 case 0: /* Apple Unicode */
3195 cmap0 = ft_face->charmaps[i];
3196 break;
3197 case 1: /* Macintosh */
3198 cmap1 = ft_face->charmaps[i];
3199 break;
3200 case 2: /* ISO */
3201 cmap2 = ft_face->charmaps[i];
3202 break;
3203 case 3: /* Microsoft */
3204 cmap3 = ft_face->charmaps[i];
3205 break;
3209 if (cmap3) /* prefer Microsoft cmap table */
3210 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3211 else if (cmap1)
3212 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3213 else if (cmap2)
3214 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3215 else if (cmap0)
3216 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3217 else if (cmap_def)
3218 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3220 return ft_err == FT_Err_Ok;
3223 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3226 /*************************************************************
3227 * WineEngCreateFontInstance
3230 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3232 GdiFont *ret;
3233 Face *face, *best, *best_bitmap;
3234 Family *family, *last_resort_family;
3235 struct list *family_elem_ptr, *face_elem_ptr;
3236 INT height, width = 0;
3237 unsigned int score = 0, new_score;
3238 signed int diff = 0, newdiff;
3239 BOOL bd, it, can_use_bitmap;
3240 LOGFONTW lf;
3241 CHARSETINFO csi;
3242 HFONTLIST *hflist;
3243 FMAT2 dcmat;
3244 FontSubst *psub = NULL;
3246 EnterCriticalSection( &freetype_cs );
3248 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3250 struct list *first_hfont = list_head(&ret->hfontlist);
3251 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3252 if(hflist->hfont == hfont)
3254 LeaveCriticalSection( &freetype_cs );
3255 return ret;
3259 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3261 LeaveCriticalSection( &freetype_cs );
3262 return NULL;
3264 lf.lfWidth = abs(lf.lfWidth);
3266 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3268 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3269 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3270 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3271 lf.lfEscapement);
3273 if(dc->GraphicsMode == GM_ADVANCED)
3274 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3275 else
3277 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3278 font scaling abilities. */
3279 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3280 dcmat.eM21 = dcmat.eM12 = 0;
3283 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3284 dcmat.eM21, dcmat.eM22);
3286 /* check the cache first */
3287 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3288 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3289 LeaveCriticalSection( &freetype_cs );
3290 return ret;
3293 TRACE("not in cache\n");
3294 if(list_empty(&font_list)) /* No fonts installed */
3296 TRACE("No fonts installed\n");
3297 LeaveCriticalSection( &freetype_cs );
3298 return NULL;
3300 if(!have_installed_roman_font)
3302 TRACE("No roman font installed\n");
3303 LeaveCriticalSection( &freetype_cs );
3304 return NULL;
3307 ret = alloc_font();
3309 ret->font_desc.matrix = dcmat;
3310 ret->font_desc.lf = lf;
3311 ret->font_desc.can_use_bitmap = can_use_bitmap;
3312 calc_hash(&ret->font_desc);
3313 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3314 hflist->hfont = hfont;
3315 list_add_head(&ret->hfontlist, &hflist->entry);
3317 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3318 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3319 original value lfCharSet. Note this is a special case for
3320 Symbol and doesn't happen at least for "Wingdings*" */
3322 if(!strcmpiW(lf.lfFaceName, SymbolW))
3323 lf.lfCharSet = SYMBOL_CHARSET;
3325 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3326 switch(lf.lfCharSet) {
3327 case DEFAULT_CHARSET:
3328 csi.fs.fsCsb[0] = 0;
3329 break;
3330 default:
3331 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3332 csi.fs.fsCsb[0] = 0;
3333 break;
3337 family = NULL;
3338 if(lf.lfFaceName[0] != '\0') {
3339 SYSTEM_LINKS *font_link;
3340 CHILD_FONT *font_link_entry;
3341 LPWSTR FaceName = lf.lfFaceName;
3344 * Check for a leading '@' this signals that the font is being
3345 * requested in tategaki mode (vertical writing substitution) but
3346 * does not affect the fontface that is to be selected.
3348 if (lf.lfFaceName[0]=='@')
3349 FaceName = &lf.lfFaceName[1];
3351 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3353 if(psub) {
3354 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3355 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3356 if (psub->to.charset != -1)
3357 lf.lfCharSet = psub->to.charset;
3360 /* We want a match on name and charset or just name if
3361 charset was DEFAULT_CHARSET. If the latter then
3362 we fixup the returned charset later in get_nearest_charset
3363 where we'll either use the charset of the current ansi codepage
3364 or if that's unavailable the first charset that the font supports.
3366 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3367 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3368 if (!strcmpiW(family->FamilyName, FaceName) ||
3369 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3371 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3372 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3373 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3374 if(face->scalable || can_use_bitmap)
3375 goto found;
3381 * Try check the SystemLink list first for a replacement font.
3382 * We may find good replacements there.
3384 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3386 if(!strcmpiW(font_link->font_name, FaceName))
3388 TRACE("found entry in system list\n");
3389 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3391 face = font_link_entry->face;
3392 family = face->family;
3393 if(csi.fs.fsCsb[0] &
3394 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3396 if(face->scalable || can_use_bitmap)
3397 goto found;
3404 psub = NULL; /* substitution is no more relevant */
3406 /* If requested charset was DEFAULT_CHARSET then try using charset
3407 corresponding to the current ansi codepage */
3408 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3410 INT acp = GetACP();
3411 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3412 FIXME("TCI failed on codepage %d\n", acp);
3413 csi.fs.fsCsb[0] = 0;
3414 } else
3415 lf.lfCharSet = csi.ciCharset;
3418 /* Face families are in the top 4 bits of lfPitchAndFamily,
3419 so mask with 0xF0 before testing */
3421 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3422 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3423 strcpyW(lf.lfFaceName, defFixed);
3424 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3425 strcpyW(lf.lfFaceName, defSerif);
3426 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3427 strcpyW(lf.lfFaceName, defSans);
3428 else
3429 strcpyW(lf.lfFaceName, defSans);
3430 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3431 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3432 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3433 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3434 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3435 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3436 if(face->scalable || can_use_bitmap)
3437 goto found;
3442 last_resort_family = NULL;
3443 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3444 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3445 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3446 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3447 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3448 if(face->scalable)
3449 goto found;
3450 if(can_use_bitmap && !last_resort_family)
3451 last_resort_family = family;
3456 if(last_resort_family) {
3457 family = last_resort_family;
3458 csi.fs.fsCsb[0] = 0;
3459 goto found;
3462 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3463 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3464 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3465 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3466 if(face->scalable) {
3467 csi.fs.fsCsb[0] = 0;
3468 WARN("just using first face for now\n");
3469 goto found;
3471 if(can_use_bitmap && !last_resort_family)
3472 last_resort_family = family;
3475 if(!last_resort_family) {
3476 FIXME("can't find a single appropriate font - bailing\n");
3477 free_font(ret);
3478 LeaveCriticalSection( &freetype_cs );
3479 return NULL;
3482 WARN("could only find a bitmap font - this will probably look awful!\n");
3483 family = last_resort_family;
3484 csi.fs.fsCsb[0] = 0;
3486 found:
3487 it = lf.lfItalic ? 1 : 0;
3488 bd = lf.lfWeight > 550 ? 1 : 0;
3490 height = lf.lfHeight;
3492 face = best = best_bitmap = NULL;
3493 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3495 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3497 BOOL italic, bold;
3499 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3500 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3501 new_score = (italic ^ it) + (bold ^ bd);
3502 if(!best || new_score <= score)
3504 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3505 italic, bold, it, bd);
3506 score = new_score;
3507 best = face;
3508 if(best->scalable && score == 0) break;
3509 if(!best->scalable)
3511 if(height > 0)
3512 newdiff = height - (signed int)(best->size.height);
3513 else
3514 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3515 if(!best_bitmap || new_score < score ||
3516 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3518 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3519 diff = newdiff;
3520 best_bitmap = best;
3521 if(score == 0 && diff == 0) break;
3527 if(best)
3528 face = best->scalable ? best : best_bitmap;
3529 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3530 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3532 ret->fs = face->fs;
3534 if(csi.fs.fsCsb[0]) {
3535 ret->charset = lf.lfCharSet;
3536 ret->codepage = csi.ciACP;
3538 else
3539 ret->charset = get_nearest_charset(face, &ret->codepage);
3541 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3542 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3544 ret->aveWidth = height ? lf.lfWidth : 0;
3546 if(!face->scalable) {
3547 /* Windows uses integer scaling factors for bitmap fonts */
3548 INT scale, scaled_height;
3550 if (height != 0) height = diff;
3551 height += face->size.height;
3553 scale = (height + face->size.height - 1) / face->size.height;
3554 scaled_height = scale * face->size.height;
3555 /* XP allows not more than 10% deviation */
3556 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3557 ret->scale_y = scale;
3559 width = face->size.x_ppem >> 6;
3560 height = face->size.y_ppem >> 6;
3562 else
3563 ret->scale_y = 1.0;
3564 TRACE("font scale y: %f\n", ret->scale_y);
3566 ret->ft_face = OpenFontFace(ret, face, width, height);
3568 if (!ret->ft_face)
3570 free_font( ret );
3571 LeaveCriticalSection( &freetype_cs );
3572 return 0;
3575 ret->ntmFlags = face->ntmFlags;
3577 if (ret->charset == SYMBOL_CHARSET &&
3578 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3579 /* No ops */
3581 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3582 /* No ops */
3584 else {
3585 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3588 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3589 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3590 ret->underline = lf.lfUnderline ? 0xff : 0;
3591 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3592 create_child_font_list(ret);
3594 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3596 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3597 if (length != GDI_ERROR)
3599 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3600 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3601 TRACE("Loaded GSUB table of %i bytes\n",length);
3605 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3607 list_add_head(&gdi_font_list, &ret->entry);
3608 LeaveCriticalSection( &freetype_cs );
3609 return ret;
3612 static void dump_gdi_font_list(void)
3614 GdiFont *gdiFont;
3615 struct list *elem_ptr;
3617 TRACE("---------- gdiFont Cache ----------\n");
3618 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3619 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3620 TRACE("gdiFont=%p %s %d\n",
3621 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3624 TRACE("---------- Unused gdiFont Cache ----------\n");
3625 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3626 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3627 TRACE("gdiFont=%p %s %d\n",
3628 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3632 /*************************************************************
3633 * WineEngDestroyFontInstance
3635 * free the gdiFont associated with this handle
3638 BOOL WineEngDestroyFontInstance(HFONT handle)
3640 GdiFont *gdiFont;
3641 HFONTLIST *hflist;
3642 BOOL ret = FALSE;
3643 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3644 int i = 0;
3646 EnterCriticalSection( &freetype_cs );
3648 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3650 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3651 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3652 if(hflist->hfont == handle)
3654 TRACE("removing child font %p from child list\n", gdiFont);
3655 list_remove(&gdiFont->entry);
3656 LeaveCriticalSection( &freetype_cs );
3657 return TRUE;
3661 TRACE("destroying hfont=%p\n", handle);
3662 if(TRACE_ON(font))
3663 dump_gdi_font_list();
3665 font_elem_ptr = list_head(&gdi_font_list);
3666 while(font_elem_ptr) {
3667 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3668 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3670 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3671 while(hfontlist_elem_ptr) {
3672 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3673 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3674 if(hflist->hfont == handle) {
3675 list_remove(&hflist->entry);
3676 HeapFree(GetProcessHeap(), 0, hflist);
3677 ret = TRUE;
3680 if(list_empty(&gdiFont->hfontlist)) {
3681 TRACE("Moving to Unused list\n");
3682 list_remove(&gdiFont->entry);
3683 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3688 font_elem_ptr = list_head(&unused_gdi_font_list);
3689 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3690 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3691 while(font_elem_ptr) {
3692 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3693 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3694 TRACE("freeing %p\n", gdiFont);
3695 list_remove(&gdiFont->entry);
3696 free_font(gdiFont);
3698 LeaveCriticalSection( &freetype_cs );
3699 return ret;
3702 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3703 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3705 GdiFont *font;
3706 LONG width, height;
3708 if (face->cached_enum_data)
3710 TRACE("Cached\n");
3711 *pelf = face->cached_enum_data->elf;
3712 *pntm = face->cached_enum_data->ntm;
3713 *ptype = face->cached_enum_data->type;
3714 return;
3717 font = alloc_font();
3719 if(face->scalable) {
3720 height = -2048; /* 2048 is the most common em size */
3721 width = 0;
3722 } else {
3723 height = face->size.y_ppem >> 6;
3724 width = face->size.x_ppem >> 6;
3726 font->scale_y = 1.0;
3728 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3730 free_font(font);
3731 return;
3734 font->name = strdupW(face->family->FamilyName);
3735 font->ntmFlags = face->ntmFlags;
3737 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3739 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3741 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3743 lstrcpynW(pelf->elfLogFont.lfFaceName,
3744 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3745 LF_FACESIZE);
3746 lstrcpynW(pelf->elfFullName,
3747 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3748 LF_FULLFACESIZE);
3749 lstrcpynW(pelf->elfStyle,
3750 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3751 LF_FACESIZE);
3753 else
3755 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3757 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3759 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3760 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3761 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3764 pntm->ntmTm.ntmFlags = face->ntmFlags;
3765 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3766 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3767 pntm->ntmFontSig = face->fs;
3769 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3771 pelf->elfLogFont.lfEscapement = 0;
3772 pelf->elfLogFont.lfOrientation = 0;
3773 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3774 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3775 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3776 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3777 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3778 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3779 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3780 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3781 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3782 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3783 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3785 *ptype = 0;
3786 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3787 *ptype |= TRUETYPE_FONTTYPE;
3788 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3789 *ptype |= DEVICE_FONTTYPE;
3790 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3791 *ptype |= RASTER_FONTTYPE;
3793 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3794 if (face->cached_enum_data)
3796 face->cached_enum_data->elf = *pelf;
3797 face->cached_enum_data->ntm = *pntm;
3798 face->cached_enum_data->type = *ptype;
3801 free_font(font);
3804 /*************************************************************
3805 * WineEngEnumFonts
3808 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3810 Family *family;
3811 Face *face;
3812 struct list *family_elem_ptr, *face_elem_ptr;
3813 ENUMLOGFONTEXW elf;
3814 NEWTEXTMETRICEXW ntm;
3815 DWORD type;
3816 FONTSIGNATURE fs;
3817 CHARSETINFO csi;
3818 LOGFONTW lf;
3819 int i;
3821 if (!plf)
3823 lf.lfCharSet = DEFAULT_CHARSET;
3824 lf.lfPitchAndFamily = 0;
3825 lf.lfFaceName[0] = 0;
3826 plf = &lf;
3829 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3831 EnterCriticalSection( &freetype_cs );
3832 if(plf->lfFaceName[0]) {
3833 FontSubst *psub;
3834 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3836 if(psub) {
3837 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3838 debugstr_w(psub->to.name));
3839 lf = *plf;
3840 strcpyW(lf.lfFaceName, psub->to.name);
3841 plf = &lf;
3844 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3845 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3846 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3847 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3848 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3849 GetEnumStructs(face, &elf, &ntm, &type);
3850 for(i = 0; i < 32; i++) {
3851 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3852 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3853 strcpyW(elf.elfScript, OEM_DOSW);
3854 i = 32; /* break out of loop */
3855 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3856 continue;
3857 else {
3858 fs.fsCsb[0] = 1L << i;
3859 fs.fsCsb[1] = 0;
3860 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3861 TCI_SRCFONTSIG))
3862 csi.ciCharset = DEFAULT_CHARSET;
3863 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3864 if(csi.ciCharset != DEFAULT_CHARSET) {
3865 elf.elfLogFont.lfCharSet =
3866 ntm.ntmTm.tmCharSet = csi.ciCharset;
3867 if(ElfScriptsW[i])
3868 strcpyW(elf.elfScript, ElfScriptsW[i]);
3869 else
3870 FIXME("Unknown elfscript for bit %d\n", i);
3873 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3874 debugstr_w(elf.elfLogFont.lfFaceName),
3875 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3876 csi.ciCharset, type, debugstr_w(elf.elfScript),
3877 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3878 ntm.ntmTm.ntmFlags);
3879 /* release section before callback (FIXME) */
3880 LeaveCriticalSection( &freetype_cs );
3881 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3882 EnterCriticalSection( &freetype_cs );
3887 } else {
3888 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3889 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3890 face_elem_ptr = list_head(&family->faces);
3891 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3892 GetEnumStructs(face, &elf, &ntm, &type);
3893 for(i = 0; i < 32; i++) {
3894 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3895 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3896 strcpyW(elf.elfScript, OEM_DOSW);
3897 i = 32; /* break out of loop */
3898 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3899 continue;
3900 else {
3901 fs.fsCsb[0] = 1L << i;
3902 fs.fsCsb[1] = 0;
3903 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3904 TCI_SRCFONTSIG))
3905 csi.ciCharset = DEFAULT_CHARSET;
3906 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3907 if(csi.ciCharset != DEFAULT_CHARSET) {
3908 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3909 csi.ciCharset;
3910 if(ElfScriptsW[i])
3911 strcpyW(elf.elfScript, ElfScriptsW[i]);
3912 else
3913 FIXME("Unknown elfscript for bit %d\n", i);
3916 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3917 debugstr_w(elf.elfLogFont.lfFaceName),
3918 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3919 csi.ciCharset, type, debugstr_w(elf.elfScript),
3920 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3921 ntm.ntmTm.ntmFlags);
3922 /* release section before callback (FIXME) */
3923 LeaveCriticalSection( &freetype_cs );
3924 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3925 EnterCriticalSection( &freetype_cs );
3929 LeaveCriticalSection( &freetype_cs );
3930 return 1;
3933 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3935 pt->x.value = vec->x >> 6;
3936 pt->x.fract = (vec->x & 0x3f) << 10;
3937 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3938 pt->y.value = vec->y >> 6;
3939 pt->y.fract = (vec->y & 0x3f) << 10;
3940 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3941 return;
3944 /***************************************************
3945 * According to the MSDN documentation on WideCharToMultiByte,
3946 * certain codepages cannot set the default_used parameter.
3947 * This returns TRUE if the codepage can set that parameter, false else
3948 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3950 static BOOL codepage_sets_default_used(UINT codepage)
3952 switch (codepage)
3954 case CP_UTF7:
3955 case CP_UTF8:
3956 case CP_SYMBOL:
3957 return FALSE;
3958 default:
3959 return TRUE;
3964 * GSUB Table handling functions
3967 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3969 const GSUB_CoverageFormat1* cf1;
3971 cf1 = (GSUB_CoverageFormat1*)table;
3973 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3975 int count = GET_BE_WORD(cf1->GlyphCount);
3976 int i;
3977 TRACE("Coverage Format 1, %i glyphs\n",count);
3978 for (i = 0; i < count; i++)
3979 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3980 return i;
3981 return -1;
3983 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3985 const GSUB_CoverageFormat2* cf2;
3986 int i;
3987 int count;
3988 cf2 = (GSUB_CoverageFormat2*)cf1;
3990 count = GET_BE_WORD(cf2->RangeCount);
3991 TRACE("Coverage Format 2, %i ranges\n",count);
3992 for (i = 0; i < count; i++)
3994 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3995 return -1;
3996 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3997 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3999 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4000 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4003 return -1;
4005 else
4006 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4008 return -1;
4011 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4013 const GSUB_ScriptList *script;
4014 const GSUB_Script *deflt = NULL;
4015 int i;
4016 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4018 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4019 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4021 const GSUB_Script *scr;
4022 int offset;
4024 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4025 scr = (GSUB_Script*)((LPBYTE)script + offset);
4027 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4028 return scr;
4029 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4030 deflt = scr;
4032 return deflt;
4035 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4037 int i;
4038 int offset;
4039 const GSUB_LangSys *Lang;
4041 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4043 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4045 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4046 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4048 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4049 return Lang;
4051 offset = GET_BE_WORD(script->DefaultLangSys);
4052 if (offset)
4054 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4055 return Lang;
4057 return NULL;
4060 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4062 int i;
4063 const GSUB_FeatureList *feature;
4064 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4066 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4067 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4069 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4070 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4072 const GSUB_Feature *feat;
4073 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4074 return feat;
4077 return NULL;
4080 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4082 int i;
4083 int offset;
4084 const GSUB_LookupList *lookup;
4085 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4087 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4088 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4090 const GSUB_LookupTable *look;
4091 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4092 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4093 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4094 if (GET_BE_WORD(look->LookupType) != 1)
4095 FIXME("We only handle SubType 1\n");
4096 else
4098 int j;
4100 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4102 const GSUB_SingleSubstFormat1 *ssf1;
4103 offset = GET_BE_WORD(look->SubTable[j]);
4104 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4105 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4107 int offset = GET_BE_WORD(ssf1->Coverage);
4108 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4109 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4111 TRACE(" Glyph 0x%x ->",glyph);
4112 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4113 TRACE(" 0x%x\n",glyph);
4116 else
4118 const GSUB_SingleSubstFormat2 *ssf2;
4119 INT index;
4120 INT offset;
4122 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4123 offset = GET_BE_WORD(ssf1->Coverage);
4124 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4125 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4126 TRACE(" Coverage index %i\n",index);
4127 if (index != -1)
4129 TRACE(" Glyph is 0x%x ->",glyph);
4130 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4131 TRACE("0x%x\n",glyph);
4137 return glyph;
4140 static const char* get_opentype_script(const GdiFont *font)
4143 * I am not sure if this is the correct way to generate our script tag
4146 switch (font->charset)
4148 case ANSI_CHARSET: return "latn";
4149 case BALTIC_CHARSET: return "latn"; /* ?? */
4150 case CHINESEBIG5_CHARSET: return "hani";
4151 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4152 case GB2312_CHARSET: return "hani";
4153 case GREEK_CHARSET: return "grek";
4154 case HANGUL_CHARSET: return "hang";
4155 case RUSSIAN_CHARSET: return "cyrl";
4156 case SHIFTJIS_CHARSET: return "kana";
4157 case TURKISH_CHARSET: return "latn"; /* ?? */
4158 case VIETNAMESE_CHARSET: return "latn";
4159 case JOHAB_CHARSET: return "latn"; /* ?? */
4160 case ARABIC_CHARSET: return "arab";
4161 case HEBREW_CHARSET: return "hebr";
4162 case THAI_CHARSET: return "thai";
4163 default: return "latn";
4167 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4169 const GSUB_Header *header;
4170 const GSUB_Script *script;
4171 const GSUB_LangSys *language;
4172 const GSUB_Feature *feature;
4174 if (!font->GSUB_Table)
4175 return glyph;
4177 header = font->GSUB_Table;
4179 script = GSUB_get_script_table(header, get_opentype_script(font));
4180 if (!script)
4182 TRACE("Script not found\n");
4183 return glyph;
4185 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4186 if (!language)
4188 TRACE("Language not found\n");
4189 return glyph;
4191 feature = GSUB_get_feature(header, language, "vrt2");
4192 if (!feature)
4193 feature = GSUB_get_feature(header, language, "vert");
4194 if (!feature)
4196 TRACE("vrt2/vert feature not found\n");
4197 return glyph;
4199 return GSUB_apply_feature(header, feature, glyph);
4202 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4204 FT_UInt glyphId;
4206 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4207 WCHAR wc = (WCHAR)glyph;
4208 BOOL default_used;
4209 BOOL *default_used_pointer;
4210 FT_UInt ret;
4211 char buf;
4212 default_used_pointer = NULL;
4213 default_used = FALSE;
4214 if (codepage_sets_default_used(font->codepage))
4215 default_used_pointer = &default_used;
4216 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4217 ret = 0;
4218 else
4219 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4220 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4221 return get_GSUB_vert_glyph(font,ret);
4224 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4225 glyph = glyph + 0xf000;
4226 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4227 return get_GSUB_vert_glyph(font,glyphId);
4230 /*************************************************************
4231 * WineEngGetGlyphIndices
4234 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4235 LPWORD pgi, DWORD flags)
4237 int i;
4238 int default_char = -1;
4240 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4242 for(i = 0; i < count; i++)
4244 pgi[i] = get_glyph_index(font, lpstr[i]);
4245 if (pgi[i] == 0)
4247 if (default_char == -1)
4249 if (FT_IS_SFNT(font->ft_face))
4251 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4252 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4254 else
4256 TEXTMETRICW textm;
4257 WineEngGetTextMetrics(font, &textm);
4258 default_char = textm.tmDefaultChar;
4261 pgi[i] = default_char;
4264 return count;
4267 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4269 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4270 return !memcmp(matrix, &identity, sizeof(FMAT2));
4273 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4275 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4276 return !memcmp(matrix, &identity, sizeof(MAT2));
4279 /*************************************************************
4280 * WineEngGetGlyphOutline
4282 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4283 * except that the first parameter is the HWINEENGFONT of the font in
4284 * question rather than an HDC.
4287 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4288 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4289 const MAT2* lpmat)
4291 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4292 FT_Face ft_face = incoming_font->ft_face;
4293 GdiFont *font = incoming_font;
4294 FT_UInt glyph_index;
4295 DWORD width, height, pitch, needed = 0;
4296 FT_Bitmap ft_bitmap;
4297 FT_Error err;
4298 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4299 FT_Angle angle = 0;
4300 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4301 double widthRatio = 1.0;
4302 FT_Matrix transMat = identityMat;
4303 FT_Matrix transMatUnrotated;
4304 BOOL needsTransform = FALSE;
4305 BOOL tategaki = (font->GSUB_Table != NULL);
4306 UINT original_index;
4308 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4309 buflen, buf, lpmat);
4311 TRACE("font transform %f %f %f %f\n",
4312 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4313 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4315 EnterCriticalSection( &freetype_cs );
4317 if(format & GGO_GLYPH_INDEX) {
4318 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4319 original_index = glyph;
4320 format &= ~GGO_GLYPH_INDEX;
4321 } else {
4322 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4323 ft_face = font->ft_face;
4324 original_index = glyph_index;
4327 /* tategaki never appears to happen to lower glyph index */
4328 if (glyph_index < TATEGAKI_LOWER_BOUND )
4329 tategaki = FALSE;
4331 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4332 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4333 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4334 font->gmsize * sizeof(GM*));
4335 } else {
4336 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4337 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4339 *lpgm = FONT_GM(font,original_index)->gm;
4340 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4341 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4342 lpgm->gmCellIncX, lpgm->gmCellIncY);
4343 LeaveCriticalSection( &freetype_cs );
4344 return 1; /* FIXME */
4348 if (!font->gm[original_index / GM_BLOCK_SIZE])
4349 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4351 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4352 load_flags |= FT_LOAD_NO_BITMAP;
4354 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4356 if(err) {
4357 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4358 LeaveCriticalSection( &freetype_cs );
4359 return GDI_ERROR;
4362 /* Scaling factor */
4363 if (font->aveWidth)
4365 TEXTMETRICW tm;
4367 WineEngGetTextMetrics(font, &tm);
4369 widthRatio = (double)font->aveWidth;
4370 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4372 else
4373 widthRatio = font->scale_y;
4375 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4376 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4378 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4379 lsb = left >> 6;
4380 bbx = (right - left) >> 6;
4382 /* Scaling transform */
4383 if (widthRatio != 1.0 || font->scale_y != 1.0)
4385 FT_Matrix scaleMat;
4386 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4387 scaleMat.xy = 0;
4388 scaleMat.yx = 0;
4389 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4391 pFT_Matrix_Multiply(&scaleMat, &transMat);
4392 needsTransform = TRUE;
4395 /* Slant transform */
4396 if (font->fake_italic) {
4397 FT_Matrix slantMat;
4399 slantMat.xx = (1 << 16);
4400 slantMat.xy = ((1 << 16) >> 2);
4401 slantMat.yx = 0;
4402 slantMat.yy = (1 << 16);
4403 pFT_Matrix_Multiply(&slantMat, &transMat);
4404 needsTransform = TRUE;
4407 /* Rotation transform */
4408 transMatUnrotated = transMat;
4409 if(font->orientation && !tategaki) {
4410 FT_Matrix rotationMat;
4411 FT_Vector vecAngle;
4412 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4413 pFT_Vector_Unit(&vecAngle, angle);
4414 rotationMat.xx = vecAngle.x;
4415 rotationMat.xy = -vecAngle.y;
4416 rotationMat.yx = -rotationMat.xy;
4417 rotationMat.yy = rotationMat.xx;
4419 pFT_Matrix_Multiply(&rotationMat, &transMat);
4420 needsTransform = TRUE;
4423 /* World transform */
4424 if (!is_identity_FMAT2(&font->font_desc.matrix))
4426 FT_Matrix worldMat;
4427 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4428 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4429 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4430 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4431 pFT_Matrix_Multiply(&worldMat, &transMat);
4432 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4433 needsTransform = TRUE;
4436 /* Extra transformation specified by caller */
4437 if (lpmat && !is_identity_MAT2(lpmat))
4439 FT_Matrix extraMat;
4440 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4441 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4442 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4443 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4444 pFT_Matrix_Multiply(&extraMat, &transMat);
4445 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4446 needsTransform = TRUE;
4449 if(!needsTransform) {
4450 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4451 bottom = (ft_face->glyph->metrics.horiBearingY -
4452 ft_face->glyph->metrics.height) & -64;
4453 lpgm->gmCellIncX = adv;
4454 lpgm->gmCellIncY = 0;
4455 } else {
4456 INT xc, yc;
4457 FT_Vector vec;
4458 for(xc = 0; xc < 2; xc++) {
4459 for(yc = 0; yc < 2; yc++) {
4460 vec.x = (ft_face->glyph->metrics.horiBearingX +
4461 xc * ft_face->glyph->metrics.width);
4462 vec.y = ft_face->glyph->metrics.horiBearingY -
4463 yc * ft_face->glyph->metrics.height;
4464 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4465 pFT_Vector_Transform(&vec, &transMat);
4466 if(xc == 0 && yc == 0) {
4467 left = right = vec.x;
4468 top = bottom = vec.y;
4469 } else {
4470 if(vec.x < left) left = vec.x;
4471 else if(vec.x > right) right = vec.x;
4472 if(vec.y < bottom) bottom = vec.y;
4473 else if(vec.y > top) top = vec.y;
4477 left = left & -64;
4478 right = (right + 63) & -64;
4479 bottom = bottom & -64;
4480 top = (top + 63) & -64;
4482 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4483 vec.x = ft_face->glyph->metrics.horiAdvance;
4484 vec.y = 0;
4485 pFT_Vector_Transform(&vec, &transMat);
4486 lpgm->gmCellIncX = (vec.x+63) >> 6;
4487 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4489 vec.x = ft_face->glyph->metrics.horiAdvance;
4490 vec.y = 0;
4491 pFT_Vector_Transform(&vec, &transMatUnrotated);
4492 adv = (vec.x+63) >> 6;
4494 lpgm->gmBlackBoxX = (right - left) >> 6;
4495 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4496 lpgm->gmptGlyphOrigin.x = left >> 6;
4497 lpgm->gmptGlyphOrigin.y = top >> 6;
4499 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4500 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4501 lpgm->gmCellIncX, lpgm->gmCellIncY);
4503 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4504 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4506 FONT_GM(font,original_index)->gm = *lpgm;
4507 FONT_GM(font,original_index)->adv = adv;
4508 FONT_GM(font,original_index)->lsb = lsb;
4509 FONT_GM(font,original_index)->bbx = bbx;
4510 FONT_GM(font,original_index)->init = TRUE;
4513 if(format == GGO_METRICS)
4515 LeaveCriticalSection( &freetype_cs );
4516 return 1; /* FIXME */
4519 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4520 TRACE("loaded a bitmap\n");
4521 LeaveCriticalSection( &freetype_cs );
4522 return GDI_ERROR;
4525 switch(format) {
4526 case GGO_BITMAP:
4527 width = lpgm->gmBlackBoxX;
4528 height = lpgm->gmBlackBoxY;
4529 pitch = ((width + 31) >> 5) << 2;
4530 needed = pitch * height;
4532 if(!buf || !buflen) break;
4534 switch(ft_face->glyph->format) {
4535 case ft_glyph_format_bitmap:
4537 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4538 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4539 INT h = ft_face->glyph->bitmap.rows;
4540 while(h--) {
4541 memcpy(dst, src, w);
4542 src += ft_face->glyph->bitmap.pitch;
4543 dst += pitch;
4545 break;
4548 case ft_glyph_format_outline:
4549 ft_bitmap.width = width;
4550 ft_bitmap.rows = height;
4551 ft_bitmap.pitch = pitch;
4552 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4553 ft_bitmap.buffer = buf;
4555 if(needsTransform) {
4556 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4559 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4561 /* Note: FreeType will only set 'black' bits for us. */
4562 memset(buf, 0, needed);
4563 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4564 break;
4566 default:
4567 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4568 LeaveCriticalSection( &freetype_cs );
4569 return GDI_ERROR;
4571 break;
4573 case GGO_GRAY2_BITMAP:
4574 case GGO_GRAY4_BITMAP:
4575 case GGO_GRAY8_BITMAP:
4576 case WINE_GGO_GRAY16_BITMAP:
4578 unsigned int mult, row, col;
4579 BYTE *start, *ptr;
4581 width = lpgm->gmBlackBoxX;
4582 height = lpgm->gmBlackBoxY;
4583 pitch = (width + 3) / 4 * 4;
4584 needed = pitch * height;
4586 if(!buf || !buflen) break;
4588 switch(ft_face->glyph->format) {
4589 case ft_glyph_format_bitmap:
4591 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4592 INT h = ft_face->glyph->bitmap.rows;
4593 INT x;
4594 while(h--) {
4595 for(x = 0; x < pitch; x++)
4597 if(x < ft_face->glyph->bitmap.width)
4598 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4599 else
4600 dst[x] = 0;
4602 src += ft_face->glyph->bitmap.pitch;
4603 dst += pitch;
4605 LeaveCriticalSection( &freetype_cs );
4606 return needed;
4608 case ft_glyph_format_outline:
4610 ft_bitmap.width = width;
4611 ft_bitmap.rows = height;
4612 ft_bitmap.pitch = pitch;
4613 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4614 ft_bitmap.buffer = buf;
4616 if(needsTransform)
4617 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4619 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4621 memset(ft_bitmap.buffer, 0, buflen);
4623 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4625 if(format == GGO_GRAY2_BITMAP)
4626 mult = 4;
4627 else if(format == GGO_GRAY4_BITMAP)
4628 mult = 16;
4629 else if(format == GGO_GRAY8_BITMAP)
4630 mult = 64;
4631 else /* format == WINE_GGO_GRAY16_BITMAP */
4633 LeaveCriticalSection( &freetype_cs );
4634 return needed;
4636 break;
4638 default:
4639 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4640 LeaveCriticalSection( &freetype_cs );
4641 return GDI_ERROR;
4644 start = buf;
4645 for(row = 0; row < height; row++) {
4646 ptr = start;
4647 for(col = 0; col < width; col++, ptr++) {
4648 *ptr = (((int)*ptr) * mult + 128) / 256;
4650 start += pitch;
4652 break;
4655 case GGO_NATIVE:
4657 int contour, point = 0, first_pt;
4658 FT_Outline *outline = &ft_face->glyph->outline;
4659 TTPOLYGONHEADER *pph;
4660 TTPOLYCURVE *ppc;
4661 DWORD pph_start, cpfx, type;
4663 if(buflen == 0) buf = NULL;
4665 if (needsTransform && buf) {
4666 pFT_Outline_Transform(outline, &transMat);
4669 for(contour = 0; contour < outline->n_contours; contour++) {
4670 pph_start = needed;
4671 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4672 first_pt = point;
4673 if(buf) {
4674 pph->dwType = TT_POLYGON_TYPE;
4675 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4677 needed += sizeof(*pph);
4678 point++;
4679 while(point <= outline->contours[contour]) {
4680 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4681 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4682 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4683 cpfx = 0;
4684 do {
4685 if(buf)
4686 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4687 cpfx++;
4688 point++;
4689 } while(point <= outline->contours[contour] &&
4690 (outline->tags[point] & FT_Curve_Tag_On) ==
4691 (outline->tags[point-1] & FT_Curve_Tag_On));
4692 /* At the end of a contour Windows adds the start point, but
4693 only for Beziers */
4694 if(point > outline->contours[contour] &&
4695 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4696 if(buf)
4697 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4698 cpfx++;
4699 } else if(point <= outline->contours[contour] &&
4700 outline->tags[point] & FT_Curve_Tag_On) {
4701 /* add closing pt for bezier */
4702 if(buf)
4703 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4704 cpfx++;
4705 point++;
4707 if(buf) {
4708 ppc->wType = type;
4709 ppc->cpfx = cpfx;
4711 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4713 if(buf)
4714 pph->cb = needed - pph_start;
4716 break;
4718 case GGO_BEZIER:
4720 /* Convert the quadratic Beziers to cubic Beziers.
4721 The parametric eqn for a cubic Bezier is, from PLRM:
4722 r(t) = at^3 + bt^2 + ct + r0
4723 with the control points:
4724 r1 = r0 + c/3
4725 r2 = r1 + (c + b)/3
4726 r3 = r0 + c + b + a
4728 A quadratic Beizer has the form:
4729 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4731 So equating powers of t leads to:
4732 r1 = 2/3 p1 + 1/3 p0
4733 r2 = 2/3 p1 + 1/3 p2
4734 and of course r0 = p0, r3 = p2
4737 int contour, point = 0, first_pt;
4738 FT_Outline *outline = &ft_face->glyph->outline;
4739 TTPOLYGONHEADER *pph;
4740 TTPOLYCURVE *ppc;
4741 DWORD pph_start, cpfx, type;
4742 FT_Vector cubic_control[4];
4743 if(buflen == 0) buf = NULL;
4745 if (needsTransform && buf) {
4746 pFT_Outline_Transform(outline, &transMat);
4749 for(contour = 0; contour < outline->n_contours; contour++) {
4750 pph_start = needed;
4751 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4752 first_pt = point;
4753 if(buf) {
4754 pph->dwType = TT_POLYGON_TYPE;
4755 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4757 needed += sizeof(*pph);
4758 point++;
4759 while(point <= outline->contours[contour]) {
4760 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4761 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4762 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4763 cpfx = 0;
4764 do {
4765 if(type == TT_PRIM_LINE) {
4766 if(buf)
4767 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4768 cpfx++;
4769 point++;
4770 } else {
4771 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4772 so cpfx = 3n */
4774 /* FIXME: Possible optimization in endpoint calculation
4775 if there are two consecutive curves */
4776 cubic_control[0] = outline->points[point-1];
4777 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4778 cubic_control[0].x += outline->points[point].x + 1;
4779 cubic_control[0].y += outline->points[point].y + 1;
4780 cubic_control[0].x >>= 1;
4781 cubic_control[0].y >>= 1;
4783 if(point+1 > outline->contours[contour])
4784 cubic_control[3] = outline->points[first_pt];
4785 else {
4786 cubic_control[3] = outline->points[point+1];
4787 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4788 cubic_control[3].x += outline->points[point].x + 1;
4789 cubic_control[3].y += outline->points[point].y + 1;
4790 cubic_control[3].x >>= 1;
4791 cubic_control[3].y >>= 1;
4794 /* r1 = 1/3 p0 + 2/3 p1
4795 r2 = 1/3 p2 + 2/3 p1 */
4796 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4797 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4798 cubic_control[2] = cubic_control[1];
4799 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4800 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4801 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4802 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4803 if(buf) {
4804 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4805 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4806 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4808 cpfx += 3;
4809 point++;
4811 } while(point <= outline->contours[contour] &&
4812 (outline->tags[point] & FT_Curve_Tag_On) ==
4813 (outline->tags[point-1] & FT_Curve_Tag_On));
4814 /* At the end of a contour Windows adds the start point,
4815 but only for Beziers and we've already done that.
4817 if(point <= outline->contours[contour] &&
4818 outline->tags[point] & FT_Curve_Tag_On) {
4819 /* This is the closing pt of a bezier, but we've already
4820 added it, so just inc point and carry on */
4821 point++;
4823 if(buf) {
4824 ppc->wType = type;
4825 ppc->cpfx = cpfx;
4827 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4829 if(buf)
4830 pph->cb = needed - pph_start;
4832 break;
4835 default:
4836 FIXME("Unsupported format %d\n", format);
4837 LeaveCriticalSection( &freetype_cs );
4838 return GDI_ERROR;
4840 LeaveCriticalSection( &freetype_cs );
4841 return needed;
4844 static BOOL get_bitmap_text_metrics(GdiFont *font)
4846 FT_Face ft_face = font->ft_face;
4847 #ifdef HAVE_FREETYPE_FTWINFNT_H
4848 FT_WinFNT_HeaderRec winfnt_header;
4849 #endif
4850 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4851 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4852 font->potm->otmSize = size;
4854 #define TM font->potm->otmTextMetrics
4855 #ifdef HAVE_FREETYPE_FTWINFNT_H
4856 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4858 TM.tmHeight = winfnt_header.pixel_height;
4859 TM.tmAscent = winfnt_header.ascent;
4860 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4861 TM.tmInternalLeading = winfnt_header.internal_leading;
4862 TM.tmExternalLeading = winfnt_header.external_leading;
4863 TM.tmAveCharWidth = winfnt_header.avg_width;
4864 TM.tmMaxCharWidth = winfnt_header.max_width;
4865 TM.tmWeight = winfnt_header.weight;
4866 TM.tmOverhang = 0;
4867 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4868 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4869 TM.tmFirstChar = winfnt_header.first_char;
4870 TM.tmLastChar = winfnt_header.last_char;
4871 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4872 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4873 TM.tmItalic = winfnt_header.italic;
4874 TM.tmUnderlined = font->underline;
4875 TM.tmStruckOut = font->strikeout;
4876 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4877 TM.tmCharSet = winfnt_header.charset;
4879 else
4880 #endif
4882 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4883 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4884 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4885 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4886 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4887 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4888 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4889 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4890 TM.tmOverhang = 0;
4891 TM.tmDigitizedAspectX = 96; /* FIXME */
4892 TM.tmDigitizedAspectY = 96; /* FIXME */
4893 TM.tmFirstChar = 1;
4894 TM.tmLastChar = 255;
4895 TM.tmDefaultChar = 32;
4896 TM.tmBreakChar = 32;
4897 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4898 TM.tmUnderlined = font->underline;
4899 TM.tmStruckOut = font->strikeout;
4900 /* NB inverted meaning of TMPF_FIXED_PITCH */
4901 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4902 TM.tmCharSet = font->charset;
4904 #undef TM
4906 return TRUE;
4910 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4912 double scale_x, scale_y;
4914 if (font->aveWidth)
4916 scale_x = (double)font->aveWidth;
4917 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4919 else
4920 scale_x = font->scale_y;
4922 scale_x *= fabs(font->font_desc.matrix.eM11);
4923 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4925 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4926 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4928 SCALE_Y(ptm->tmHeight);
4929 SCALE_Y(ptm->tmAscent);
4930 SCALE_Y(ptm->tmDescent);
4931 SCALE_Y(ptm->tmInternalLeading);
4932 SCALE_Y(ptm->tmExternalLeading);
4933 SCALE_Y(ptm->tmOverhang);
4935 SCALE_X(ptm->tmAveCharWidth);
4936 SCALE_X(ptm->tmMaxCharWidth);
4938 #undef SCALE_X
4939 #undef SCALE_Y
4942 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4944 double scale_x, scale_y;
4946 if (font->aveWidth)
4948 scale_x = (double)font->aveWidth;
4949 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4951 else
4952 scale_x = font->scale_y;
4954 scale_x *= fabs(font->font_desc.matrix.eM11);
4955 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4957 scale_font_metrics(font, &potm->otmTextMetrics);
4959 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4960 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4962 SCALE_Y(potm->otmAscent);
4963 SCALE_Y(potm->otmDescent);
4964 SCALE_Y(potm->otmLineGap);
4965 SCALE_Y(potm->otmsCapEmHeight);
4966 SCALE_Y(potm->otmsXHeight);
4967 SCALE_Y(potm->otmrcFontBox.top);
4968 SCALE_Y(potm->otmrcFontBox.bottom);
4969 SCALE_X(potm->otmrcFontBox.left);
4970 SCALE_X(potm->otmrcFontBox.right);
4971 SCALE_Y(potm->otmMacAscent);
4972 SCALE_Y(potm->otmMacDescent);
4973 SCALE_Y(potm->otmMacLineGap);
4974 SCALE_X(potm->otmptSubscriptSize.x);
4975 SCALE_Y(potm->otmptSubscriptSize.y);
4976 SCALE_X(potm->otmptSubscriptOffset.x);
4977 SCALE_Y(potm->otmptSubscriptOffset.y);
4978 SCALE_X(potm->otmptSuperscriptSize.x);
4979 SCALE_Y(potm->otmptSuperscriptSize.y);
4980 SCALE_X(potm->otmptSuperscriptOffset.x);
4981 SCALE_Y(potm->otmptSuperscriptOffset.y);
4982 SCALE_Y(potm->otmsStrikeoutSize);
4983 SCALE_Y(potm->otmsStrikeoutPosition);
4984 SCALE_Y(potm->otmsUnderscoreSize);
4985 SCALE_Y(potm->otmsUnderscorePosition);
4987 #undef SCALE_X
4988 #undef SCALE_Y
4991 /*************************************************************
4992 * WineEngGetTextMetrics
4995 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4997 EnterCriticalSection( &freetype_cs );
4998 if(!font->potm) {
4999 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5000 if(!get_bitmap_text_metrics(font))
5002 LeaveCriticalSection( &freetype_cs );
5003 return FALSE;
5006 if(!font->potm)
5008 LeaveCriticalSection( &freetype_cs );
5009 return FALSE;
5011 *ptm = font->potm->otmTextMetrics;
5012 scale_font_metrics(font, ptm);
5013 LeaveCriticalSection( &freetype_cs );
5014 return TRUE;
5018 /*************************************************************
5019 * WineEngGetOutlineTextMetrics
5022 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5023 OUTLINETEXTMETRICW *potm)
5025 FT_Face ft_face = font->ft_face;
5026 UINT needed, lenfam, lensty, ret;
5027 TT_OS2 *pOS2;
5028 TT_HoriHeader *pHori;
5029 TT_Postscript *pPost;
5030 FT_Fixed x_scale, y_scale;
5031 WCHAR *family_nameW, *style_nameW;
5032 static const WCHAR spaceW[] = {' ', '\0'};
5033 char *cp;
5034 INT ascent, descent;
5036 TRACE("font=%p\n", font);
5038 if(!FT_IS_SCALABLE(ft_face))
5039 return 0;
5041 EnterCriticalSection( &freetype_cs );
5043 if(font->potm) {
5044 if(cbSize >= font->potm->otmSize)
5046 memcpy(potm, font->potm, font->potm->otmSize);
5047 scale_outline_font_metrics(font, potm);
5049 LeaveCriticalSection( &freetype_cs );
5050 return font->potm->otmSize;
5054 needed = sizeof(*potm);
5056 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5057 family_nameW = strdupW(font->name);
5059 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5060 * sizeof(WCHAR);
5061 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5062 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5063 style_nameW, lensty/sizeof(WCHAR));
5065 /* These names should be read from the TT name table */
5067 /* length of otmpFamilyName */
5068 needed += lenfam;
5070 /* length of otmpFaceName */
5071 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5072 needed += lenfam; /* just the family name */
5073 } else {
5074 needed += lenfam + lensty; /* family + " " + style */
5077 /* length of otmpStyleName */
5078 needed += lensty;
5080 /* length of otmpFullName */
5081 needed += lenfam + lensty;
5084 x_scale = ft_face->size->metrics.x_scale;
5085 y_scale = ft_face->size->metrics.y_scale;
5087 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5088 if(!pOS2) {
5089 FIXME("Can't find OS/2 table - not TT font?\n");
5090 ret = 0;
5091 goto end;
5094 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5095 if(!pHori) {
5096 FIXME("Can't find HHEA table - not TT font?\n");
5097 ret = 0;
5098 goto end;
5101 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5103 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",
5104 pOS2->usWinAscent, pOS2->usWinDescent,
5105 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5106 ft_face->ascender, ft_face->descender, ft_face->height,
5107 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5108 ft_face->bbox.yMax, ft_face->bbox.yMin);
5110 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5111 font->potm->otmSize = needed;
5113 #define TM font->potm->otmTextMetrics
5115 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5116 ascent = pHori->Ascender;
5117 descent = -pHori->Descender;
5118 } else {
5119 ascent = pOS2->usWinAscent;
5120 descent = pOS2->usWinDescent;
5123 if(font->yMax) {
5124 TM.tmAscent = font->yMax;
5125 TM.tmDescent = -font->yMin;
5126 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5127 } else {
5128 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5129 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5130 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5131 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5134 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5136 /* MSDN says:
5137 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5139 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5140 ((ascent + descent) -
5141 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5143 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5144 if (TM.tmAveCharWidth == 0) {
5145 TM.tmAveCharWidth = 1;
5147 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5148 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
5149 TM.tmOverhang = 0;
5150 TM.tmDigitizedAspectX = 300;
5151 TM.tmDigitizedAspectY = 300;
5152 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5153 * symbol range to 0 - f0ff
5155 if (font->charset == SYMBOL_CHARSET)
5157 TM.tmFirstChar = 0;
5158 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5160 else
5162 TM.tmFirstChar = pOS2->usFirstCharIndex;
5163 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5165 TM.tmLastChar = pOS2->usLastCharIndex;
5166 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5167 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5168 TM.tmUnderlined = font->underline;
5169 TM.tmStruckOut = font->strikeout;
5171 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5172 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5173 (pOS2->version == 0xFFFFU ||
5174 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5175 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5176 else
5177 TM.tmPitchAndFamily = 0;
5179 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5180 case PAN_FAMILY_SCRIPT:
5181 TM.tmPitchAndFamily |= FF_SCRIPT;
5182 break;
5183 case PAN_FAMILY_DECORATIVE:
5184 case PAN_FAMILY_PICTORIAL:
5185 TM.tmPitchAndFamily |= FF_DECORATIVE;
5186 break;
5187 case PAN_FAMILY_TEXT_DISPLAY:
5188 if(TM.tmPitchAndFamily == 0) /* fixed */
5189 TM.tmPitchAndFamily = FF_MODERN;
5190 else {
5191 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5192 case PAN_SERIF_NORMAL_SANS:
5193 case PAN_SERIF_OBTUSE_SANS:
5194 case PAN_SERIF_PERP_SANS:
5195 TM.tmPitchAndFamily |= FF_SWISS;
5196 break;
5197 default:
5198 TM.tmPitchAndFamily |= FF_ROMAN;
5201 break;
5202 default:
5203 TM.tmPitchAndFamily |= FF_DONTCARE;
5206 if(FT_IS_SCALABLE(ft_face))
5207 TM.tmPitchAndFamily |= TMPF_VECTOR;
5209 if(FT_IS_SFNT(ft_face))
5211 if (font->ntmFlags & NTM_PS_OPENTYPE)
5212 TM.tmPitchAndFamily |= TMPF_DEVICE;
5213 else
5214 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5217 TM.tmCharSet = font->charset;
5219 font->potm->otmFiller = 0;
5220 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5221 font->potm->otmfsSelection = pOS2->fsSelection;
5222 font->potm->otmfsType = pOS2->fsType;
5223 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5224 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5225 font->potm->otmItalicAngle = 0; /* POST table */
5226 font->potm->otmEMSquare = ft_face->units_per_EM;
5227 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5228 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5229 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5230 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5231 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5232 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5233 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5234 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5235 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5236 font->potm->otmMacAscent = TM.tmAscent;
5237 font->potm->otmMacDescent = -TM.tmDescent;
5238 font->potm->otmMacLineGap = font->potm->otmLineGap;
5239 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5240 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5241 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5242 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5243 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5244 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5245 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5246 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5247 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5248 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5249 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5250 if(!pPost) {
5251 font->potm->otmsUnderscoreSize = 0;
5252 font->potm->otmsUnderscorePosition = 0;
5253 } else {
5254 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5255 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5257 #undef TM
5259 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5260 cp = (char*)font->potm + sizeof(*font->potm);
5261 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5262 strcpyW((WCHAR*)cp, family_nameW);
5263 cp += lenfam;
5264 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5265 strcpyW((WCHAR*)cp, style_nameW);
5266 cp += lensty;
5267 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5268 strcpyW((WCHAR*)cp, family_nameW);
5269 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5270 strcatW((WCHAR*)cp, spaceW);
5271 strcatW((WCHAR*)cp, style_nameW);
5272 cp += lenfam + lensty;
5273 } else
5274 cp += lenfam;
5275 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5276 strcpyW((WCHAR*)cp, family_nameW);
5277 strcatW((WCHAR*)cp, spaceW);
5278 strcatW((WCHAR*)cp, style_nameW);
5279 ret = needed;
5281 if(potm && needed <= cbSize)
5283 memcpy(potm, font->potm, font->potm->otmSize);
5284 scale_outline_font_metrics(font, potm);
5287 end:
5288 HeapFree(GetProcessHeap(), 0, style_nameW);
5289 HeapFree(GetProcessHeap(), 0, family_nameW);
5291 LeaveCriticalSection( &freetype_cs );
5292 return ret;
5295 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5297 HFONTLIST *hfontlist;
5298 child->font = alloc_font();
5299 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5300 if(!child->font->ft_face)
5302 free_font(child->font);
5303 child->font = NULL;
5304 return FALSE;
5307 child->font->ntmFlags = child->face->ntmFlags;
5308 child->font->orientation = font->orientation;
5309 child->font->scale_y = font->scale_y;
5310 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5311 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5312 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5313 child->font->base_font = font;
5314 list_add_head(&child_font_list, &child->font->entry);
5315 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5316 return TRUE;
5319 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5321 FT_UInt g;
5322 CHILD_FONT *child_font;
5324 if(font->base_font)
5325 font = font->base_font;
5327 *linked_font = font;
5329 if((*glyph = get_glyph_index(font, c)))
5330 return TRUE;
5332 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5334 if(!child_font->font)
5335 if(!load_child_font(font, child_font))
5336 continue;
5338 if(!child_font->font->ft_face)
5339 continue;
5340 g = get_glyph_index(child_font->font, c);
5341 if(g)
5343 *glyph = g;
5344 *linked_font = child_font->font;
5345 return TRUE;
5348 return FALSE;
5351 /*************************************************************
5352 * WineEngGetCharWidth
5355 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5356 LPINT buffer)
5358 UINT c;
5359 GLYPHMETRICS gm;
5360 FT_UInt glyph_index;
5361 GdiFont *linked_font;
5363 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5365 EnterCriticalSection( &freetype_cs );
5366 for(c = firstChar; c <= lastChar; c++) {
5367 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5368 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5369 &gm, 0, NULL, NULL);
5370 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5372 LeaveCriticalSection( &freetype_cs );
5373 return TRUE;
5376 /*************************************************************
5377 * WineEngGetCharABCWidths
5380 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5381 LPABC buffer)
5383 UINT c;
5384 GLYPHMETRICS gm;
5385 FT_UInt glyph_index;
5386 GdiFont *linked_font;
5388 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5390 if(!FT_IS_SCALABLE(font->ft_face))
5391 return FALSE;
5393 EnterCriticalSection( &freetype_cs );
5395 for(c = firstChar; c <= lastChar; c++) {
5396 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5397 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5398 &gm, 0, NULL, NULL);
5399 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5400 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5401 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5402 FONT_GM(linked_font,glyph_index)->bbx;
5404 LeaveCriticalSection( &freetype_cs );
5405 return TRUE;
5408 /*************************************************************
5409 * WineEngGetCharABCWidthsI
5412 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5413 LPABC buffer)
5415 UINT c;
5416 GLYPHMETRICS gm;
5417 FT_UInt glyph_index;
5418 GdiFont *linked_font;
5420 if(!FT_HAS_HORIZONTAL(font->ft_face))
5421 return FALSE;
5423 EnterCriticalSection( &freetype_cs );
5425 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5426 if (!pgi)
5427 for(c = firstChar; c < firstChar+count; c++) {
5428 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5429 &gm, 0, NULL, NULL);
5430 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5431 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5432 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5433 - FONT_GM(linked_font,c)->bbx;
5435 else
5436 for(c = 0; c < count; c++) {
5437 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5438 &gm, 0, NULL, NULL);
5439 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5440 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5441 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5442 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5445 LeaveCriticalSection( &freetype_cs );
5446 return TRUE;
5449 /*************************************************************
5450 * WineEngGetTextExtentExPoint
5453 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5454 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5456 INT idx;
5457 INT nfit = 0, ext;
5458 GLYPHMETRICS gm;
5459 TEXTMETRICW tm;
5460 FT_UInt glyph_index;
5461 GdiFont *linked_font;
5463 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5464 max_ext, size);
5466 EnterCriticalSection( &freetype_cs );
5468 size->cx = 0;
5469 WineEngGetTextMetrics(font, &tm);
5470 size->cy = tm.tmHeight;
5472 for(idx = 0; idx < count; idx++) {
5473 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5474 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5475 &gm, 0, NULL, NULL);
5476 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5477 ext = size->cx;
5478 if (! pnfit || ext <= max_ext) {
5479 ++nfit;
5480 if (dxs)
5481 dxs[idx] = ext;
5485 if (pnfit)
5486 *pnfit = nfit;
5488 LeaveCriticalSection( &freetype_cs );
5489 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5490 return TRUE;
5493 /*************************************************************
5494 * WineEngGetTextExtentExPointI
5497 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5498 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5500 INT idx;
5501 INT nfit = 0, ext;
5502 GLYPHMETRICS gm;
5503 TEXTMETRICW tm;
5505 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5507 EnterCriticalSection( &freetype_cs );
5509 size->cx = 0;
5510 WineEngGetTextMetrics(font, &tm);
5511 size->cy = tm.tmHeight;
5513 for(idx = 0; idx < count; idx++) {
5514 WineEngGetGlyphOutline(font, indices[idx],
5515 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5516 NULL);
5517 size->cx += FONT_GM(font,indices[idx])->adv;
5518 ext = size->cx;
5519 if (! pnfit || ext <= max_ext) {
5520 ++nfit;
5521 if (dxs)
5522 dxs[idx] = ext;
5526 if (pnfit)
5527 *pnfit = nfit;
5529 LeaveCriticalSection( &freetype_cs );
5530 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5531 return TRUE;
5534 /*************************************************************
5535 * WineEngGetFontData
5538 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5539 DWORD cbData)
5541 FT_Face ft_face = font->ft_face;
5542 FT_ULong len;
5543 FT_Error err;
5545 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5546 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5547 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5549 if(!FT_IS_SFNT(ft_face))
5550 return GDI_ERROR;
5552 if(!buf || !cbData)
5553 len = 0;
5554 else
5555 len = cbData;
5557 if(table) { /* MS tags differ in endianness from FT ones */
5558 table = table >> 24 | table << 24 |
5559 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5562 /* make sure value of len is the value freetype says it needs */
5563 if(buf && len)
5565 FT_ULong needed = 0;
5566 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5567 if( !err && needed < len) len = needed;
5569 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5571 if(err) {
5572 TRACE("Can't find table %c%c%c%c\n",
5573 /* bytes were reversed */
5574 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5575 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5576 return GDI_ERROR;
5578 return len;
5581 /*************************************************************
5582 * WineEngGetTextFace
5585 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5587 INT n = strlenW(font->name) + 1;
5588 if(str) {
5589 lstrcpynW(str, font->name, count);
5590 return min(count, n);
5591 } else
5592 return n;
5595 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5597 if (fs) *fs = font->fs;
5598 return font->charset;
5601 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5603 GdiFont *font = dc->gdiFont, *linked_font;
5604 struct list *first_hfont;
5605 BOOL ret;
5607 EnterCriticalSection( &freetype_cs );
5608 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5609 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5610 if(font == linked_font)
5611 *new_hfont = dc->hFont;
5612 else
5614 first_hfont = list_head(&linked_font->hfontlist);
5615 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5617 LeaveCriticalSection( &freetype_cs );
5618 return ret;
5621 /* Retrieve a list of supported Unicode ranges for a given font.
5622 * Can be called with NULL gs to calculate the buffer size. Returns
5623 * the number of ranges found.
5625 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5627 DWORD num_ranges = 0;
5629 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5631 FT_UInt glyph_code;
5632 FT_ULong char_code, char_code_prev;
5634 glyph_code = 0;
5635 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5637 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5638 face->num_glyphs, glyph_code, char_code);
5640 if (!glyph_code) return 0;
5642 if (gs)
5644 gs->ranges[0].wcLow = (USHORT)char_code;
5645 gs->ranges[0].cGlyphs = 0;
5646 gs->cGlyphsSupported = 0;
5649 num_ranges = 1;
5650 while (glyph_code)
5652 if (char_code < char_code_prev)
5654 ERR("expected increasing char code from FT_Get_Next_Char\n");
5655 return 0;
5657 if (char_code - char_code_prev > 1)
5659 num_ranges++;
5660 if (gs)
5662 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5663 gs->ranges[num_ranges - 1].cGlyphs = 1;
5664 gs->cGlyphsSupported++;
5667 else if (gs)
5669 gs->ranges[num_ranges - 1].cGlyphs++;
5670 gs->cGlyphsSupported++;
5672 char_code_prev = char_code;
5673 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5676 else
5677 FIXME("encoding %u not supported\n", face->charmap->encoding);
5679 return num_ranges;
5682 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5684 DWORD size = 0;
5685 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5687 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5688 if (glyphset)
5690 glyphset->cbThis = size;
5691 glyphset->cRanges = num_ranges;
5693 return size;
5696 /*************************************************************
5697 * FontIsLinked
5699 BOOL WineEngFontIsLinked(GdiFont *font)
5701 BOOL ret;
5702 EnterCriticalSection( &freetype_cs );
5703 ret = !list_empty(&font->child_fonts);
5704 LeaveCriticalSection( &freetype_cs );
5705 return ret;
5708 static BOOL is_hinting_enabled(void)
5710 /* Use the >= 2.2.0 function if available */
5711 if(pFT_Get_TrueType_Engine_Type)
5713 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5714 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5716 #ifdef FT_DRIVER_HAS_HINTER
5717 else
5719 FT_Module mod;
5721 /* otherwise if we've been compiled with < 2.2.0 headers
5722 use the internal macro */
5723 mod = pFT_Get_Module(library, "truetype");
5724 if(mod && FT_DRIVER_HAS_HINTER(mod))
5725 return TRUE;
5727 #endif
5729 return FALSE;
5732 /*************************************************************************
5733 * GetRasterizerCaps (GDI32.@)
5735 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5737 static int hinting = -1;
5739 if(hinting == -1)
5741 hinting = is_hinting_enabled();
5742 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5745 lprs->nSize = sizeof(RASTERIZER_STATUS);
5746 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5747 lprs->nLanguageID = 0;
5748 return TRUE;
5751 /*************************************************************************
5752 * Kerning support for TrueType fonts
5754 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5756 struct TT_kern_table
5758 USHORT version;
5759 USHORT nTables;
5762 struct TT_kern_subtable
5764 USHORT version;
5765 USHORT length;
5766 union
5768 USHORT word;
5769 struct
5771 USHORT horizontal : 1;
5772 USHORT minimum : 1;
5773 USHORT cross_stream: 1;
5774 USHORT override : 1;
5775 USHORT reserved1 : 4;
5776 USHORT format : 8;
5777 } bits;
5778 } coverage;
5781 struct TT_format0_kern_subtable
5783 USHORT nPairs;
5784 USHORT searchRange;
5785 USHORT entrySelector;
5786 USHORT rangeShift;
5789 struct TT_kern_pair
5791 USHORT left;
5792 USHORT right;
5793 short value;
5796 static DWORD parse_format0_kern_subtable(GdiFont *font,
5797 const struct TT_format0_kern_subtable *tt_f0_ks,
5798 const USHORT *glyph_to_char,
5799 KERNINGPAIR *kern_pair, DWORD cPairs)
5801 USHORT i, nPairs;
5802 const struct TT_kern_pair *tt_kern_pair;
5804 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5806 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5808 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5809 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5810 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5812 if (!kern_pair || !cPairs)
5813 return nPairs;
5815 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5817 nPairs = min(nPairs, cPairs);
5819 for (i = 0; i < nPairs; i++)
5821 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5822 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5823 /* this algorithm appears to better match what Windows does */
5824 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5825 if (kern_pair->iKernAmount < 0)
5827 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5828 kern_pair->iKernAmount -= font->ppem;
5830 else if (kern_pair->iKernAmount > 0)
5832 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5833 kern_pair->iKernAmount += font->ppem;
5835 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5837 TRACE("left %u right %u value %d\n",
5838 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5840 kern_pair++;
5842 TRACE("copied %u entries\n", nPairs);
5843 return nPairs;
5846 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5848 DWORD length;
5849 void *buf;
5850 const struct TT_kern_table *tt_kern_table;
5851 const struct TT_kern_subtable *tt_kern_subtable;
5852 USHORT i, nTables;
5853 USHORT *glyph_to_char;
5855 EnterCriticalSection( &freetype_cs );
5856 if (font->total_kern_pairs != (DWORD)-1)
5858 if (cPairs && kern_pair)
5860 cPairs = min(cPairs, font->total_kern_pairs);
5861 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5862 LeaveCriticalSection( &freetype_cs );
5863 return cPairs;
5865 LeaveCriticalSection( &freetype_cs );
5866 return font->total_kern_pairs;
5869 font->total_kern_pairs = 0;
5871 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5873 if (length == GDI_ERROR)
5875 TRACE("no kerning data in the font\n");
5876 LeaveCriticalSection( &freetype_cs );
5877 return 0;
5880 buf = HeapAlloc(GetProcessHeap(), 0, length);
5881 if (!buf)
5883 WARN("Out of memory\n");
5884 LeaveCriticalSection( &freetype_cs );
5885 return 0;
5888 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5890 /* build a glyph index to char code map */
5891 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5892 if (!glyph_to_char)
5894 WARN("Out of memory allocating a glyph index to char code map\n");
5895 HeapFree(GetProcessHeap(), 0, buf);
5896 LeaveCriticalSection( &freetype_cs );
5897 return 0;
5900 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5902 FT_UInt glyph_code;
5903 FT_ULong char_code;
5905 glyph_code = 0;
5906 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5908 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5909 font->ft_face->num_glyphs, glyph_code, char_code);
5911 while (glyph_code)
5913 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5915 /* FIXME: This doesn't match what Windows does: it does some fancy
5916 * things with duplicate glyph index to char code mappings, while
5917 * we just avoid overriding existing entries.
5919 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5920 glyph_to_char[glyph_code] = (USHORT)char_code;
5922 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5925 else
5927 ULONG n;
5929 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5930 for (n = 0; n <= 65535; n++)
5931 glyph_to_char[n] = (USHORT)n;
5934 tt_kern_table = buf;
5935 nTables = GET_BE_WORD(tt_kern_table->nTables);
5936 TRACE("version %u, nTables %u\n",
5937 GET_BE_WORD(tt_kern_table->version), nTables);
5939 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5941 for (i = 0; i < nTables; i++)
5943 struct TT_kern_subtable tt_kern_subtable_copy;
5945 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5946 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5947 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5949 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5950 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5951 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5953 /* According to the TrueType specification this is the only format
5954 * that will be properly interpreted by Windows and OS/2
5956 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5958 DWORD new_chunk, old_total = font->total_kern_pairs;
5960 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5961 glyph_to_char, NULL, 0);
5962 font->total_kern_pairs += new_chunk;
5964 if (!font->kern_pairs)
5965 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5966 font->total_kern_pairs * sizeof(*font->kern_pairs));
5967 else
5968 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5969 font->total_kern_pairs * sizeof(*font->kern_pairs));
5971 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5972 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5974 else
5975 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5977 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5980 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5981 HeapFree(GetProcessHeap(), 0, buf);
5983 if (cPairs && kern_pair)
5985 cPairs = min(cPairs, font->total_kern_pairs);
5986 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5987 LeaveCriticalSection( &freetype_cs );
5988 return cPairs;
5990 LeaveCriticalSection( &freetype_cs );
5991 return font->total_kern_pairs;
5994 #else /* HAVE_FREETYPE */
5996 /*************************************************************************/
5998 BOOL WineEngInit(void)
6000 return FALSE;
6002 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6004 return NULL;
6006 BOOL WineEngDestroyFontInstance(HFONT hfont)
6008 return FALSE;
6011 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6013 return 1;
6016 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6017 LPWORD pgi, DWORD flags)
6019 return GDI_ERROR;
6022 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6023 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6024 const MAT2* lpmat)
6026 ERR("called but we don't have FreeType\n");
6027 return GDI_ERROR;
6030 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6032 ERR("called but we don't have FreeType\n");
6033 return FALSE;
6036 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6037 OUTLINETEXTMETRICW *potm)
6039 ERR("called but we don't have FreeType\n");
6040 return 0;
6043 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6044 LPINT buffer)
6046 ERR("called but we don't have FreeType\n");
6047 return FALSE;
6050 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6051 LPABC buffer)
6053 ERR("called but we don't have FreeType\n");
6054 return FALSE;
6057 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6058 LPABC buffer)
6060 ERR("called but we don't have FreeType\n");
6061 return FALSE;
6064 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6065 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6067 ERR("called but we don't have FreeType\n");
6068 return FALSE;
6071 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6072 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6074 ERR("called but we don't have FreeType\n");
6075 return FALSE;
6078 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6079 DWORD cbData)
6081 ERR("called but we don't have FreeType\n");
6082 return GDI_ERROR;
6085 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6087 ERR("called but we don't have FreeType\n");
6088 return 0;
6091 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6093 FIXME(":stub\n");
6094 return 1;
6097 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6099 FIXME(":stub\n");
6100 return TRUE;
6103 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6105 FIXME(":stub\n");
6106 return NULL;
6109 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6111 FIXME(":stub\n");
6112 return DEFAULT_CHARSET;
6115 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6117 return FALSE;
6120 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6122 FIXME("(%p, %p): stub\n", font, glyphset);
6123 return 0;
6126 BOOL WineEngFontIsLinked(GdiFont *font)
6128 return FALSE;
6131 /*************************************************************************
6132 * GetRasterizerCaps (GDI32.@)
6134 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6136 lprs->nSize = sizeof(RASTERIZER_STATUS);
6137 lprs->wFlags = 0;
6138 lprs->nLanguageID = 0;
6139 return TRUE;
6142 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6144 ERR("called but we don't have FreeType\n");
6145 return 0;
6148 #endif /* HAVE_FREETYPE */