winhttp: Implement WinHttpQueryAuthSchemes.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobcb351db7693ef0bd763baf19331e0713c7f5480c
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;
338 DWORD cache_num;
341 typedef struct {
342 struct list entry;
343 const WCHAR *font_name;
344 struct list links;
345 } SYSTEM_LINKS;
347 #define GM_BLOCK_SIZE 128
348 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
350 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
351 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
352 #define UNUSED_CACHE_SIZE 10
353 static struct list child_font_list = LIST_INIT(child_font_list);
354 static struct list system_links = LIST_INIT(system_links);
356 static struct list font_subst_list = LIST_INIT(font_subst_list);
358 static struct list font_list = LIST_INIT(font_list);
360 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
361 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
362 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
364 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
365 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
366 'W','i','n','d','o','w','s','\\',
367 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
368 'F','o','n','t','s','\0'};
370 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
371 'W','i','n','d','o','w','s',' ','N','T','\\',
372 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
373 'F','o','n','t','s','\0'};
375 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
376 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
377 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
378 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
380 static const WCHAR * const SystemFontValues[4] = {
381 System_Value,
382 OEMFont_Value,
383 FixedSys_Value,
384 NULL
387 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
388 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
390 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
391 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
392 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
393 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
394 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
395 'E','u','r','o','p','e','a','n','\0'};
396 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
397 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
398 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
399 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
400 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
401 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
402 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
403 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
404 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
405 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
406 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
407 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
409 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
410 WesternW, /*00*/
411 Central_EuropeanW,
412 CyrillicW,
413 GreekW,
414 TurkishW,
415 HebrewW,
416 ArabicW,
417 BalticW,
418 VietnameseW, /*08*/
419 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
420 ThaiW,
421 JapaneseW,
422 CHINESE_GB2312W,
423 HangulW,
424 CHINESE_BIG5W,
425 Hangul_Johab_W,
426 NULL, NULL, /*23*/
427 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
428 SymbolW /*31*/
431 typedef struct {
432 WCHAR *name;
433 INT charset;
434 } NameCs;
436 typedef struct tagFontSubst {
437 struct list entry;
438 NameCs from;
439 NameCs to;
440 } FontSubst;
442 struct font_mapping
444 struct list entry;
445 int refcount;
446 dev_t dev;
447 ino_t ino;
448 void *data;
449 size_t size;
452 static struct list mappings_list = LIST_INIT( mappings_list );
454 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
456 static CRITICAL_SECTION freetype_cs;
457 static CRITICAL_SECTION_DEBUG critsect_debug =
459 0, 0, &freetype_cs,
460 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
461 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
463 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
465 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
467 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
468 static BOOL use_default_fallback = FALSE;
470 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
472 /****************************************
473 * Notes on .fon files
475 * The fonts System, FixedSys and Terminal are special. There are typically multiple
476 * versions installed for different resolutions and codepages. Windows stores which one to use
477 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
478 * Key Meaning
479 * FIXEDFON.FON FixedSys
480 * FONTS.FON System
481 * OEMFONT.FON Terminal
482 * LogPixels Current dpi set by the display control panel applet
483 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
484 * also has a LogPixels value that appears to mirror this)
486 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
487 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
488 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
489 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
490 * so that makes sense.
492 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
493 * to be mapped into the registry on Windows 2000 at least).
494 * I have
495 * woafont=app850.fon
496 * ega80woa.fon=ega80850.fon
497 * ega40woa.fon=ega40850.fon
498 * cga80woa.fon=cga80850.fon
499 * cga40woa.fon=cga40850.fon
502 /* These are all structures needed for the GSUB table */
504 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
505 #define TATEGAKI_LOWER_BOUND 0x02F1
507 typedef struct {
508 DWORD version;
509 WORD ScriptList;
510 WORD FeatureList;
511 WORD LookupList;
512 } GSUB_Header;
514 typedef struct {
515 CHAR ScriptTag[4];
516 WORD Script;
517 } GSUB_ScriptRecord;
519 typedef struct {
520 WORD ScriptCount;
521 GSUB_ScriptRecord ScriptRecord[1];
522 } GSUB_ScriptList;
524 typedef struct {
525 CHAR LangSysTag[4];
526 WORD LangSys;
527 } GSUB_LangSysRecord;
529 typedef struct {
530 WORD DefaultLangSys;
531 WORD LangSysCount;
532 GSUB_LangSysRecord LangSysRecord[1];
533 } GSUB_Script;
535 typedef struct {
536 WORD LookupOrder; /* Reserved */
537 WORD ReqFeatureIndex;
538 WORD FeatureCount;
539 WORD FeatureIndex[1];
540 } GSUB_LangSys;
542 typedef struct {
543 CHAR FeatureTag[4];
544 WORD Feature;
545 } GSUB_FeatureRecord;
547 typedef struct {
548 WORD FeatureCount;
549 GSUB_FeatureRecord FeatureRecord[1];
550 } GSUB_FeatureList;
552 typedef struct {
553 WORD FeatureParams; /* Reserved */
554 WORD LookupCount;
555 WORD LookupListIndex[1];
556 } GSUB_Feature;
558 typedef struct {
559 WORD LookupCount;
560 WORD Lookup[1];
561 } GSUB_LookupList;
563 typedef struct {
564 WORD LookupType;
565 WORD LookupFlag;
566 WORD SubTableCount;
567 WORD SubTable[1];
568 } GSUB_LookupTable;
570 typedef struct {
571 WORD CoverageFormat;
572 WORD GlyphCount;
573 WORD GlyphArray[1];
574 } GSUB_CoverageFormat1;
576 typedef struct {
577 WORD Start;
578 WORD End;
579 WORD StartCoverageIndex;
580 } GSUB_RangeRecord;
582 typedef struct {
583 WORD CoverageFormat;
584 WORD RangeCount;
585 GSUB_RangeRecord RangeRecord[1];
586 } GSUB_CoverageFormat2;
588 typedef struct {
589 WORD SubstFormat; /* = 1 */
590 WORD Coverage;
591 WORD DeltaGlyphID;
592 } GSUB_SingleSubstFormat1;
594 typedef struct {
595 WORD SubstFormat; /* = 2 */
596 WORD Coverage;
597 WORD GlyphCount;
598 WORD Substitute[1];
599 }GSUB_SingleSubstFormat2;
601 #ifdef HAVE_CARBON_CARBON_H
602 static char *find_cache_dir(void)
604 FSRef ref;
605 OSErr err;
606 static char cached_path[MAX_PATH];
607 static const char *wine = "/Wine", *fonts = "/Fonts";
609 if(*cached_path) return cached_path;
611 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
612 if(err != noErr)
614 WARN("can't create cached data folder\n");
615 return NULL;
617 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
618 if(err != noErr)
620 WARN("can't create cached data path\n");
621 *cached_path = '\0';
622 return NULL;
624 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
626 ERR("Could not create full path\n");
627 *cached_path = '\0';
628 return NULL;
630 strcat(cached_path, wine);
632 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
634 WARN("Couldn't mkdir %s\n", cached_path);
635 *cached_path = '\0';
636 return NULL;
638 strcat(cached_path, fonts);
639 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
641 WARN("Couldn't mkdir %s\n", cached_path);
642 *cached_path = '\0';
643 return NULL;
645 return cached_path;
648 /******************************************************************
649 * expand_mac_font
651 * Extracts individual TrueType font files from a Mac suitcase font
652 * and saves them into the user's caches directory (see
653 * find_cache_dir()).
654 * Returns a NULL terminated array of filenames.
656 * We do this because they are apps that try to read ttf files
657 * themselves and they don't like Mac suitcase files.
659 static char **expand_mac_font(const char *path)
661 FSRef ref;
662 SInt16 res_ref;
663 OSStatus s;
664 unsigned int idx;
665 const char *out_dir;
666 const char *filename;
667 int output_len;
668 struct {
669 char **array;
670 unsigned int size, max_size;
671 } ret;
673 TRACE("path %s\n", path);
675 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
676 if(s != noErr)
678 WARN("failed to get ref\n");
679 return NULL;
682 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
683 if(s != noErr)
685 TRACE("no data fork, so trying resource fork\n");
686 res_ref = FSOpenResFile(&ref, fsRdPerm);
687 if(res_ref == -1)
689 TRACE("unable to open resource fork\n");
690 return NULL;
694 ret.size = 0;
695 ret.max_size = 10;
696 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
697 if(!ret.array)
699 CloseResFile(res_ref);
700 return NULL;
703 out_dir = find_cache_dir();
705 filename = strrchr(path, '/');
706 if(!filename) filename = path;
707 else filename++;
709 /* output filename has the form out_dir/filename_%04x.ttf */
710 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
712 UseResFile(res_ref);
713 idx = 1;
714 while(1)
716 FamRec *fam_rec;
717 unsigned short *num_faces_ptr, num_faces, face;
718 AsscEntry *assoc;
719 Handle fond;
720 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
722 fond = Get1IndResource(fond_res, idx);
723 if(!fond) break;
724 TRACE("got fond resource %d\n", idx);
725 HLock(fond);
727 fam_rec = *(FamRec**)fond;
728 num_faces_ptr = (unsigned short *)(fam_rec + 1);
729 num_faces = GET_BE_WORD(*num_faces_ptr);
730 num_faces++;
731 assoc = (AsscEntry*)(num_faces_ptr + 1);
732 TRACE("num faces %04x\n", num_faces);
733 for(face = 0; face < num_faces; face++, assoc++)
735 Handle sfnt;
736 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
737 unsigned short size, font_id;
738 char *output;
740 size = GET_BE_WORD(assoc->fontSize);
741 font_id = GET_BE_WORD(assoc->fontID);
742 if(size != 0)
744 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
745 continue;
748 TRACE("trying to load sfnt id %04x\n", font_id);
749 sfnt = GetResource(sfnt_res, font_id);
750 if(!sfnt)
752 TRACE("can't get sfnt resource %04x\n", font_id);
753 continue;
756 output = HeapAlloc(GetProcessHeap(), 0, output_len);
757 if(output)
759 int fd;
761 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
763 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
764 if(fd != -1 || errno == EEXIST)
766 if(fd != -1)
768 unsigned char *sfnt_data;
770 HLock(sfnt);
771 sfnt_data = *(unsigned char**)sfnt;
772 write(fd, sfnt_data, GetHandleSize(sfnt));
773 HUnlock(sfnt);
774 close(fd);
776 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
778 ret.max_size *= 2;
779 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
781 ret.array[ret.size++] = output;
783 else
785 WARN("unable to create %s\n", output);
786 HeapFree(GetProcessHeap(), 0, output);
789 ReleaseResource(sfnt);
791 HUnlock(fond);
792 ReleaseResource(fond);
793 idx++;
795 CloseResFile(res_ref);
797 return ret.array;
800 #endif /* HAVE_CARBON_CARBON_H */
802 static inline BOOL is_win9x(void)
804 return GetVersion() & 0x80000000;
807 This function builds an FT_Fixed from a double. It fails if the absolute
808 value of the float number is greater than 32768.
810 static inline FT_Fixed FT_FixedFromFloat(double f)
812 return f * 0x10000;
816 This function builds an FT_Fixed from a FIXED. It simply put f.value
817 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
819 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
821 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
825 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
827 Family *family;
828 Face *face;
829 const char *file;
830 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
831 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
833 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
834 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
836 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
838 if(face_name && strcmpiW(face_name, family->FamilyName))
839 continue;
840 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
842 if (!face->file)
843 continue;
844 file = strrchr(face->file, '/');
845 if(!file)
846 file = face->file;
847 else
848 file++;
849 if(!strcasecmp(file, file_nameA))
851 HeapFree(GetProcessHeap(), 0, file_nameA);
852 return face;
856 HeapFree(GetProcessHeap(), 0, file_nameA);
857 return NULL;
860 static Family *find_family_from_name(const WCHAR *name)
862 Family *family;
864 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
866 if(!strcmpiW(family->FamilyName, name))
867 return family;
870 return NULL;
873 static void DumpSubstList(void)
875 FontSubst *psub;
877 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
879 if(psub->from.charset != -1 || psub->to.charset != -1)
880 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
881 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
882 else
883 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
884 debugstr_w(psub->to.name));
886 return;
889 static LPWSTR strdupW(LPCWSTR p)
891 LPWSTR ret;
892 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
893 ret = HeapAlloc(GetProcessHeap(), 0, len);
894 memcpy(ret, p, len);
895 return ret;
898 static LPSTR strdupA(LPCSTR p)
900 LPSTR ret;
901 DWORD len = (strlen(p) + 1);
902 ret = HeapAlloc(GetProcessHeap(), 0, len);
903 memcpy(ret, p, len);
904 return ret;
907 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
908 INT from_charset)
910 FontSubst *element;
912 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
914 if(!strcmpiW(element->from.name, from_name) &&
915 (element->from.charset == from_charset ||
916 element->from.charset == -1))
917 return element;
920 return NULL;
923 #define ADD_FONT_SUBST_FORCE 1
925 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
927 FontSubst *from_exist, *to_exist;
929 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
931 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
933 list_remove(&from_exist->entry);
934 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
935 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
936 HeapFree(GetProcessHeap(), 0, from_exist);
937 from_exist = NULL;
940 if(!from_exist)
942 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
944 if(to_exist)
946 HeapFree(GetProcessHeap(), 0, subst->to.name);
947 subst->to.name = strdupW(to_exist->to.name);
950 list_add_tail(subst_list, &subst->entry);
952 return TRUE;
955 HeapFree(GetProcessHeap(), 0, subst->from.name);
956 HeapFree(GetProcessHeap(), 0, subst->to.name);
957 HeapFree(GetProcessHeap(), 0, subst);
958 return FALSE;
961 static void split_subst_info(NameCs *nc, LPSTR str)
963 CHAR *p = strrchr(str, ',');
964 DWORD len;
966 nc->charset = -1;
967 if(p && *(p+1)) {
968 nc->charset = strtol(p+1, NULL, 10);
969 *p = '\0';
971 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
972 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
973 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
976 static void LoadSubstList(void)
978 FontSubst *psub;
979 HKEY hkey;
980 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
981 LPSTR value;
982 LPVOID data;
984 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
985 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
986 &hkey) == ERROR_SUCCESS) {
988 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
989 &valuelen, &datalen, NULL, NULL);
991 valuelen++; /* returned value doesn't include room for '\0' */
992 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
993 data = HeapAlloc(GetProcessHeap(), 0, datalen);
995 dlen = datalen;
996 vlen = valuelen;
997 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
998 &dlen) == ERROR_SUCCESS) {
999 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1001 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1002 split_subst_info(&psub->from, value);
1003 split_subst_info(&psub->to, data);
1005 /* Win 2000 doesn't allow mapping between different charsets
1006 or mapping of DEFAULT_CHARSET */
1007 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1008 psub->to.charset == DEFAULT_CHARSET) {
1009 HeapFree(GetProcessHeap(), 0, psub->to.name);
1010 HeapFree(GetProcessHeap(), 0, psub->from.name);
1011 HeapFree(GetProcessHeap(), 0, psub);
1012 } else {
1013 add_font_subst(&font_subst_list, psub, 0);
1015 /* reset dlen and vlen */
1016 dlen = datalen;
1017 vlen = valuelen;
1019 HeapFree(GetProcessHeap(), 0, data);
1020 HeapFree(GetProcessHeap(), 0, value);
1021 RegCloseKey(hkey);
1025 static WCHAR *get_familyname(FT_Face ft_face)
1027 WCHAR *family = NULL;
1028 FT_SfntName name;
1029 FT_UInt num_names, name_index, i;
1031 if(FT_IS_SFNT(ft_face))
1033 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1035 for(name_index = 0; name_index < num_names; name_index++)
1037 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1039 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1040 (name.language_id == GetUserDefaultLCID()) &&
1041 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1042 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1044 /* String is not nul terminated and string_len is a byte length. */
1045 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1046 for(i = 0; i < name.string_len / 2; i++)
1048 WORD *tmp = (WORD *)&name.string[i * 2];
1049 family[i] = GET_BE_WORD(*tmp);
1051 family[i] = 0;
1053 TRACE("Got localised name %s\n", debugstr_w(family));
1054 return family;
1060 return NULL;
1064 /*****************************************************************
1065 * load_sfnt_table
1067 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1068 * of FreeType that don't export this function.
1071 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1074 FT_Error err;
1076 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1077 if(pFT_Load_Sfnt_Table)
1079 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1081 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1082 else /* Do it the hard way */
1084 TT_Face tt_face = (TT_Face) ft_face;
1085 SFNT_Interface *sfnt;
1086 if (FT_Version.major==2 && FT_Version.minor==0)
1088 /* 2.0.x */
1089 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1091 else
1093 /* A field was added in the middle of the structure in 2.1.x */
1094 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1096 err = sfnt->load_any(tt_face, table, offset, buf, len);
1098 #else
1099 else
1101 static int msg;
1102 if(!msg)
1104 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1105 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1106 "Please upgrade your freetype library.\n");
1107 msg++;
1109 err = FT_Err_Unimplemented_Feature;
1111 #endif
1112 return err;
1115 static inline int TestStyles(DWORD flags, DWORD styles)
1117 return (flags & styles) == styles;
1120 static int StyleOrdering(Face *face)
1122 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1123 return 3;
1124 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1125 return 2;
1126 if (TestStyles(face->ntmFlags, NTM_BOLD))
1127 return 1;
1128 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1129 return 0;
1131 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1132 debugstr_w(face->family->FamilyName),
1133 debugstr_w(face->StyleName),
1134 face->ntmFlags);
1136 return 9999;
1139 /* Add a style of face to a font family using an ordering of the list such
1140 that regular fonts come before bold and italic, and single styles come
1141 before compound styles. */
1142 static void AddFaceToFamily(Face *face, Family *family)
1144 struct list *entry;
1146 LIST_FOR_EACH( entry, &family->faces )
1148 Face *ent = LIST_ENTRY(entry, Face, entry);
1149 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1151 list_add_before( entry, &face->entry );
1154 #define ADDFONT_EXTERNAL_FONT 0x01
1155 #define ADDFONT_FORCE_BITMAP 0x02
1156 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1158 FT_Face ft_face;
1159 TT_OS2 *pOS2;
1160 TT_Header *pHeader = NULL;
1161 WCHAR *english_family, *localised_family, *StyleW;
1162 DWORD len;
1163 Family *family;
1164 Face *face;
1165 struct list *family_elem_ptr, *face_elem_ptr;
1166 FT_Error err;
1167 FT_Long face_index = 0, num_faces;
1168 #ifdef HAVE_FREETYPE_FTWINFNT_H
1169 FT_WinFNT_HeaderRec winfnt_header;
1170 #endif
1171 int i, bitmap_num, internal_leading;
1172 FONTSIGNATURE fs;
1174 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1175 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1177 #ifdef HAVE_CARBON_CARBON_H
1178 if(file && !fake_family)
1180 char **mac_list = expand_mac_font(file);
1181 if(mac_list)
1183 BOOL had_one = FALSE;
1184 char **cursor;
1185 for(cursor = mac_list; *cursor; cursor++)
1187 had_one = TRUE;
1188 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1189 HeapFree(GetProcessHeap(), 0, *cursor);
1191 HeapFree(GetProcessHeap(), 0, mac_list);
1192 if(had_one)
1193 return 1;
1196 #endif /* HAVE_CARBON_CARBON_H */
1198 do {
1199 char *family_name = fake_family;
1201 if (file)
1203 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1204 err = pFT_New_Face(library, file, face_index, &ft_face);
1205 } else
1207 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1208 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1211 if(err != 0) {
1212 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1213 return 0;
1216 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*/
1217 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1218 pFT_Done_Face(ft_face);
1219 return 0;
1222 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1223 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1224 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1225 pFT_Done_Face(ft_face);
1226 return 0;
1229 if(FT_IS_SFNT(ft_face))
1231 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1232 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1233 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1235 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1236 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1237 pFT_Done_Face(ft_face);
1238 return 0;
1241 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1242 we don't want to load these. */
1243 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1245 FT_ULong len = 0;
1247 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1249 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1250 pFT_Done_Face(ft_face);
1251 return 0;
1256 if(!ft_face->family_name || !ft_face->style_name) {
1257 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1258 pFT_Done_Face(ft_face);
1259 return 0;
1262 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1264 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1265 pFT_Done_Face(ft_face);
1266 return 0;
1269 if (target_family)
1271 localised_family = get_familyname(ft_face);
1272 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1274 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1275 HeapFree(GetProcessHeap(), 0, localised_family);
1276 num_faces = ft_face->num_faces;
1277 pFT_Done_Face(ft_face);
1278 continue;
1280 HeapFree(GetProcessHeap(), 0, localised_family);
1283 if(!family_name)
1284 family_name = ft_face->family_name;
1286 bitmap_num = 0;
1287 do {
1288 My_FT_Bitmap_Size *size = NULL;
1289 FT_ULong tmp_size;
1291 if(!FT_IS_SCALABLE(ft_face))
1292 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1294 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1295 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1296 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1298 localised_family = NULL;
1299 if(!fake_family) {
1300 localised_family = get_familyname(ft_face);
1301 if(localised_family && !strcmpW(localised_family, english_family)) {
1302 HeapFree(GetProcessHeap(), 0, localised_family);
1303 localised_family = NULL;
1307 family = NULL;
1308 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1309 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1310 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1311 break;
1312 family = NULL;
1314 if(!family) {
1315 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1316 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1317 list_init(&family->faces);
1318 list_add_tail(&font_list, &family->entry);
1320 if(localised_family) {
1321 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1322 subst->from.name = strdupW(english_family);
1323 subst->from.charset = -1;
1324 subst->to.name = strdupW(localised_family);
1325 subst->to.charset = -1;
1326 add_font_subst(&font_subst_list, subst, 0);
1329 HeapFree(GetProcessHeap(), 0, localised_family);
1330 HeapFree(GetProcessHeap(), 0, english_family);
1332 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1333 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1334 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1336 internal_leading = 0;
1337 memset(&fs, 0, sizeof(fs));
1339 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1340 if(pOS2) {
1341 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1342 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1343 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1344 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1345 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1346 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1347 if(pOS2->version == 0) {
1348 FT_UInt dummy;
1350 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1351 fs.fsCsb[0] |= FS_LATIN1;
1352 else
1353 fs.fsCsb[0] |= FS_SYMBOL;
1356 #ifdef HAVE_FREETYPE_FTWINFNT_H
1357 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1358 CHARSETINFO csi;
1359 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1360 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1361 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1362 fs = csi.fs;
1363 internal_leading = winfnt_header.internal_leading;
1365 #endif
1367 face_elem_ptr = list_head(&family->faces);
1368 while(face_elem_ptr) {
1369 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1370 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1371 if(!strcmpW(face->StyleName, StyleW) &&
1372 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1373 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1374 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1375 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1377 if(fake_family) {
1378 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1379 HeapFree(GetProcessHeap(), 0, StyleW);
1380 pFT_Done_Face(ft_face);
1381 return 1;
1383 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1384 TRACE("Original font is newer so skipping this one\n");
1385 HeapFree(GetProcessHeap(), 0, StyleW);
1386 pFT_Done_Face(ft_face);
1387 return 1;
1388 } else {
1389 TRACE("Replacing original with this one\n");
1390 list_remove(&face->entry);
1391 HeapFree(GetProcessHeap(), 0, face->file);
1392 HeapFree(GetProcessHeap(), 0, face->StyleName);
1393 HeapFree(GetProcessHeap(), 0, face);
1394 break;
1398 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1399 face->cached_enum_data = NULL;
1400 face->StyleName = StyleW;
1401 if (file)
1403 face->file = strdupA(file);
1404 face->font_data_ptr = NULL;
1405 face->font_data_size = 0;
1407 else
1409 face->file = NULL;
1410 face->font_data_ptr = font_data_ptr;
1411 face->font_data_size = font_data_size;
1413 face->face_index = face_index;
1414 face->ntmFlags = 0;
1415 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1416 face->ntmFlags |= NTM_ITALIC;
1417 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1418 face->ntmFlags |= NTM_BOLD;
1419 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1420 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1421 face->family = family;
1422 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1423 face->fs = fs;
1424 memset(&face->fs_links, 0, sizeof(face->fs_links));
1426 if(FT_IS_SCALABLE(ft_face)) {
1427 memset(&face->size, 0, sizeof(face->size));
1428 face->scalable = TRUE;
1429 } else {
1430 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1431 size->height, size->width, size->size >> 6,
1432 size->x_ppem >> 6, size->y_ppem >> 6);
1433 face->size.height = size->height;
1434 face->size.width = size->width;
1435 face->size.size = size->size;
1436 face->size.x_ppem = size->x_ppem;
1437 face->size.y_ppem = size->y_ppem;
1438 face->size.internal_leading = internal_leading;
1439 face->scalable = FALSE;
1442 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1443 tmp_size = 0;
1444 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1446 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1447 face->ntmFlags |= NTM_PS_OPENTYPE;
1450 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1451 face->fs.fsCsb[0], face->fs.fsCsb[1],
1452 face->fs.fsUsb[0], face->fs.fsUsb[1],
1453 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1456 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1457 for(i = 0; i < ft_face->num_charmaps; i++) {
1458 switch(ft_face->charmaps[i]->encoding) {
1459 case FT_ENCODING_UNICODE:
1460 case FT_ENCODING_APPLE_ROMAN:
1461 face->fs.fsCsb[0] |= FS_LATIN1;
1462 break;
1463 case FT_ENCODING_MS_SYMBOL:
1464 face->fs.fsCsb[0] |= FS_SYMBOL;
1465 break;
1466 default:
1467 break;
1472 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1473 have_installed_roman_font = TRUE;
1475 AddFaceToFamily(face, family);
1477 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1479 num_faces = ft_face->num_faces;
1480 pFT_Done_Face(ft_face);
1481 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1482 debugstr_w(StyleW));
1483 } while(num_faces > ++face_index);
1484 return num_faces;
1487 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1489 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1492 static void DumpFontList(void)
1494 Family *family;
1495 Face *face;
1496 struct list *family_elem_ptr, *face_elem_ptr;
1498 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1499 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1500 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1501 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1502 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1503 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1504 if(!face->scalable)
1505 TRACE(" %d", face->size.height);
1506 TRACE("\n");
1509 return;
1512 /***********************************************************
1513 * The replacement list is a way to map an entire font
1514 * family onto another family. For example adding
1516 * [HKCU\Software\Wine\Fonts\Replacements]
1517 * "Wingdings"="Winedings"
1519 * would enumerate the Winedings font both as Winedings and
1520 * Wingdings. However if a real Wingdings font is present the
1521 * replacement does not take place.
1524 static void LoadReplaceList(void)
1526 HKEY hkey;
1527 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1528 LPWSTR value;
1529 LPVOID data;
1530 Family *family;
1531 Face *face;
1532 struct list *family_elem_ptr, *face_elem_ptr;
1533 CHAR familyA[400];
1535 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1536 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1538 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1539 &valuelen, &datalen, NULL, NULL);
1541 valuelen++; /* returned value doesn't include room for '\0' */
1542 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1543 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1545 dlen = datalen;
1546 vlen = valuelen;
1547 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1548 &dlen) == ERROR_SUCCESS) {
1549 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1550 /* "NewName"="Oldname" */
1551 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1553 /* Find the old family and hence all of the font files
1554 in that family */
1555 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1556 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1557 if(!strcmpiW(family->FamilyName, data)) {
1558 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1559 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1560 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1561 debugstr_w(face->StyleName), familyA);
1562 /* Now add a new entry with the new family name */
1563 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1565 break;
1568 /* reset dlen and vlen */
1569 dlen = datalen;
1570 vlen = valuelen;
1572 HeapFree(GetProcessHeap(), 0, data);
1573 HeapFree(GetProcessHeap(), 0, value);
1574 RegCloseKey(hkey);
1578 /*************************************************************
1579 * init_system_links
1581 static BOOL init_system_links(void)
1583 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1584 'W','i','n','d','o','w','s',' ','N','T','\\',
1585 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1586 'S','y','s','t','e','m','L','i','n','k',0};
1587 HKEY hkey;
1588 BOOL ret = FALSE;
1589 DWORD type, max_val, max_data, val_len, data_len, index;
1590 WCHAR *value, *data;
1591 WCHAR *entry, *next;
1592 SYSTEM_LINKS *font_link, *system_font_link;
1593 CHILD_FONT *child_font;
1594 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1595 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1596 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1597 FONTSIGNATURE fs;
1598 Family *family;
1599 Face *face;
1600 FontSubst *psub;
1602 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1604 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1605 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1606 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1607 val_len = max_val + 1;
1608 data_len = max_data;
1609 index = 0;
1610 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1612 TRACE("%s:\n", debugstr_w(value));
1614 memset(&fs, 0, sizeof(fs));
1615 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1616 psub = get_font_subst(&font_subst_list, value, -1);
1617 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1618 list_init(&font_link->links);
1619 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1621 WCHAR *face_name;
1622 CHILD_FONT *child_font;
1624 TRACE("\t%s\n", debugstr_w(entry));
1626 next = entry + strlenW(entry) + 1;
1628 face_name = strchrW(entry, ',');
1629 if(face_name)
1631 *face_name++ = 0;
1632 while(isspaceW(*face_name))
1633 face_name++;
1635 psub = get_font_subst(&font_subst_list, face_name, -1);
1636 if(psub)
1637 face_name = psub->to.name;
1639 face = find_face_from_filename(entry, face_name);
1640 if(!face)
1642 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1643 continue;
1646 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1647 child_font->face = face;
1648 child_font->font = NULL;
1649 fs.fsCsb[0] |= face->fs.fsCsb[0];
1650 fs.fsCsb[1] |= face->fs.fsCsb[1];
1651 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1652 list_add_tail(&font_link->links, &child_font->entry);
1654 family = find_family_from_name(font_link->font_name);
1655 if(family)
1657 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1659 face->fs_links = fs;
1662 list_add_tail(&system_links, &font_link->entry);
1663 val_len = max_val + 1;
1664 data_len = max_data;
1667 HeapFree(GetProcessHeap(), 0, value);
1668 HeapFree(GetProcessHeap(), 0, data);
1669 RegCloseKey(hkey);
1672 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1673 that Tahoma has */
1675 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1676 system_font_link->font_name = strdupW(System);
1677 list_init(&system_font_link->links);
1679 face = find_face_from_filename(tahoma_ttf, Tahoma);
1680 if(face)
1682 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1683 child_font->face = face;
1684 child_font->font = NULL;
1685 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1686 list_add_tail(&system_font_link->links, &child_font->entry);
1688 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1690 if(!strcmpiW(font_link->font_name, Tahoma))
1692 CHILD_FONT *font_link_entry;
1693 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1695 CHILD_FONT *new_child;
1696 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1697 new_child->face = font_link_entry->face;
1698 new_child->font = NULL;
1699 list_add_tail(&system_font_link->links, &new_child->entry);
1701 break;
1704 list_add_tail(&system_links, &system_font_link->entry);
1705 return ret;
1708 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1710 DIR *dir;
1711 struct dirent *dent;
1712 char path[MAX_PATH];
1714 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1716 dir = opendir(dirname);
1717 if(!dir) {
1718 WARN("Can't open directory %s\n", debugstr_a(dirname));
1719 return FALSE;
1721 while((dent = readdir(dir)) != NULL) {
1722 struct stat statbuf;
1724 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1725 continue;
1727 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1729 sprintf(path, "%s/%s", dirname, dent->d_name);
1731 if(stat(path, &statbuf) == -1)
1733 WARN("Can't stat %s\n", debugstr_a(path));
1734 continue;
1736 if(S_ISDIR(statbuf.st_mode))
1737 ReadFontDir(path, external_fonts);
1738 else
1739 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1741 closedir(dir);
1742 return TRUE;
1745 static void load_fontconfig_fonts(void)
1747 #ifdef SONAME_LIBFONTCONFIG
1748 void *fc_handle = NULL;
1749 FcConfig *config;
1750 FcPattern *pat;
1751 FcObjectSet *os;
1752 FcFontSet *fontset;
1753 int i, len;
1754 char *file;
1755 const char *ext;
1757 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1758 if(!fc_handle) {
1759 TRACE("Wine cannot find the fontconfig library (%s).\n",
1760 SONAME_LIBFONTCONFIG);
1761 return;
1763 #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;}
1764 LOAD_FUNCPTR(FcConfigGetCurrent);
1765 LOAD_FUNCPTR(FcFontList);
1766 LOAD_FUNCPTR(FcFontSetDestroy);
1767 LOAD_FUNCPTR(FcInit);
1768 LOAD_FUNCPTR(FcObjectSetAdd);
1769 LOAD_FUNCPTR(FcObjectSetCreate);
1770 LOAD_FUNCPTR(FcObjectSetDestroy);
1771 LOAD_FUNCPTR(FcPatternCreate);
1772 LOAD_FUNCPTR(FcPatternDestroy);
1773 LOAD_FUNCPTR(FcPatternGetBool);
1774 LOAD_FUNCPTR(FcPatternGetString);
1775 #undef LOAD_FUNCPTR
1777 if(!pFcInit()) return;
1779 config = pFcConfigGetCurrent();
1780 pat = pFcPatternCreate();
1781 os = pFcObjectSetCreate();
1782 pFcObjectSetAdd(os, FC_FILE);
1783 pFcObjectSetAdd(os, FC_SCALABLE);
1784 fontset = pFcFontList(config, pat, os);
1785 if(!fontset) return;
1786 for(i = 0; i < fontset->nfont; i++) {
1787 FcBool scalable;
1789 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1790 continue;
1791 TRACE("fontconfig: %s\n", file);
1793 /* We're just interested in OT/TT fonts for now, so this hack just
1794 picks up the scalable fonts without extensions .pf[ab] to save time
1795 loading every other font */
1797 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1799 TRACE("not scalable\n");
1800 continue;
1803 len = strlen( file );
1804 if(len < 4) continue;
1805 ext = &file[ len - 3 ];
1806 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1807 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1809 pFcFontSetDestroy(fontset);
1810 pFcObjectSetDestroy(os);
1811 pFcPatternDestroy(pat);
1812 sym_not_found:
1813 #endif
1814 return;
1817 static BOOL load_font_from_data_dir(LPCWSTR file)
1819 BOOL ret = FALSE;
1820 const char *data_dir = wine_get_data_dir();
1822 if (!data_dir) data_dir = wine_get_build_dir();
1824 if (data_dir)
1826 INT len;
1827 char *unix_name;
1829 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1831 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1833 strcpy(unix_name, data_dir);
1834 strcat(unix_name, "/fonts/");
1836 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1838 EnterCriticalSection( &freetype_cs );
1839 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1840 LeaveCriticalSection( &freetype_cs );
1841 HeapFree(GetProcessHeap(), 0, unix_name);
1843 return ret;
1846 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1848 static const WCHAR slashW[] = {'\\','\0'};
1849 BOOL ret = FALSE;
1850 WCHAR windowsdir[MAX_PATH];
1851 char *unixname;
1853 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1854 strcatW(windowsdir, fontsW);
1855 strcatW(windowsdir, slashW);
1856 strcatW(windowsdir, file);
1857 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1858 EnterCriticalSection( &freetype_cs );
1859 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1860 LeaveCriticalSection( &freetype_cs );
1861 HeapFree(GetProcessHeap(), 0, unixname);
1863 return ret;
1866 static void load_system_fonts(void)
1868 HKEY hkey;
1869 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1870 const WCHAR * const *value;
1871 DWORD dlen, type;
1872 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1873 char *unixname;
1875 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1876 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1877 strcatW(windowsdir, fontsW);
1878 for(value = SystemFontValues; *value; value++) {
1879 dlen = sizeof(data);
1880 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1881 type == REG_SZ) {
1882 BOOL added = FALSE;
1884 sprintfW(pathW, fmtW, windowsdir, data);
1885 if((unixname = wine_get_unix_file_name(pathW))) {
1886 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1887 HeapFree(GetProcessHeap(), 0, unixname);
1889 if (!added)
1890 load_font_from_data_dir(data);
1893 RegCloseKey(hkey);
1897 /*************************************************************
1899 * This adds registry entries for any externally loaded fonts
1900 * (fonts from fontconfig or FontDirs). It also deletes entries
1901 * of no longer existing fonts.
1904 static void update_reg_entries(void)
1906 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1907 LPWSTR valueW;
1908 DWORD len, len_fam;
1909 Family *family;
1910 Face *face;
1911 struct list *family_elem_ptr, *face_elem_ptr;
1912 WCHAR *file;
1913 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1914 static const WCHAR spaceW[] = {' ', '\0'};
1915 char *path;
1917 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1918 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1919 ERR("Can't create Windows font reg key\n");
1920 goto end;
1923 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1924 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1925 ERR("Can't create Windows font reg key\n");
1926 goto end;
1929 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1930 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1931 ERR("Can't create external font reg key\n");
1932 goto end;
1935 /* enumerate the fonts and add external ones to the two keys */
1937 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1938 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1939 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1940 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1941 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1942 if(!face->external) continue;
1943 len = len_fam;
1944 if (!(face->ntmFlags & NTM_REGULAR))
1945 len = len_fam + strlenW(face->StyleName) + 1;
1946 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1947 strcpyW(valueW, family->FamilyName);
1948 if(len != len_fam) {
1949 strcatW(valueW, spaceW);
1950 strcatW(valueW, face->StyleName);
1952 strcatW(valueW, TrueType);
1954 file = wine_get_dos_file_name(face->file);
1955 if(file)
1956 len = strlenW(file) + 1;
1957 else
1959 if((path = strrchr(face->file, '/')) == NULL)
1960 path = face->file;
1961 else
1962 path++;
1963 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1965 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1966 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1968 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1969 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1970 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1972 HeapFree(GetProcessHeap(), 0, file);
1973 HeapFree(GetProcessHeap(), 0, valueW);
1976 end:
1977 if(external_key) RegCloseKey(external_key);
1978 if(win9x_key) RegCloseKey(win9x_key);
1979 if(winnt_key) RegCloseKey(winnt_key);
1980 return;
1983 static void delete_external_font_keys(void)
1985 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1986 DWORD dlen, vlen, datalen, valuelen, i, type;
1987 LPWSTR valueW;
1988 LPVOID data;
1990 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1991 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1992 ERR("Can't create Windows font reg key\n");
1993 goto end;
1996 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1997 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1998 ERR("Can't create Windows font reg key\n");
1999 goto end;
2002 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2003 ERR("Can't create external font reg key\n");
2004 goto end;
2007 /* Delete all external fonts added last time */
2009 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2010 &valuelen, &datalen, NULL, NULL);
2011 valuelen++; /* returned value doesn't include room for '\0' */
2012 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2013 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2015 dlen = datalen * sizeof(WCHAR);
2016 vlen = valuelen;
2017 i = 0;
2018 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2019 &dlen) == ERROR_SUCCESS) {
2021 RegDeleteValueW(winnt_key, valueW);
2022 RegDeleteValueW(win9x_key, valueW);
2023 /* reset dlen and vlen */
2024 dlen = datalen;
2025 vlen = valuelen;
2027 HeapFree(GetProcessHeap(), 0, data);
2028 HeapFree(GetProcessHeap(), 0, valueW);
2030 /* Delete the old external fonts key */
2031 RegCloseKey(external_key);
2032 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2034 end:
2035 if(win9x_key) RegCloseKey(win9x_key);
2036 if(winnt_key) RegCloseKey(winnt_key);
2039 /*************************************************************
2040 * WineEngAddFontResourceEx
2043 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2045 INT ret = 0;
2046 if (ft_handle) /* do it only if we have freetype up and running */
2048 char *unixname;
2050 if(flags)
2051 FIXME("Ignoring flags %x\n", flags);
2053 if((unixname = wine_get_unix_file_name(file)))
2055 EnterCriticalSection( &freetype_cs );
2056 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2057 LeaveCriticalSection( &freetype_cs );
2058 HeapFree(GetProcessHeap(), 0, unixname);
2060 if (!ret && !strchrW(file, '\\')) {
2061 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2062 ret = load_font_from_winfonts_dir(file);
2063 if (!ret) {
2064 /* Try in datadir/fonts (or builddir/fonts),
2065 * needed for Magic the Gathering Online
2067 ret = load_font_from_data_dir(file);
2071 return ret;
2074 /*************************************************************
2075 * WineEngAddFontMemResourceEx
2078 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2080 if (ft_handle) /* do it only if we have freetype up and running */
2082 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2084 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2085 memcpy(pFontCopy, pbFont, cbFont);
2087 EnterCriticalSection( &freetype_cs );
2088 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2089 LeaveCriticalSection( &freetype_cs );
2091 if (*pcFonts == 0)
2093 TRACE("AddFontToList failed\n");
2094 HeapFree(GetProcessHeap(), 0, pFontCopy);
2095 return NULL;
2097 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2098 * For now return something unique but quite random
2100 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2101 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2104 *pcFonts = 0;
2105 return 0;
2108 /*************************************************************
2109 * WineEngRemoveFontResourceEx
2112 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2114 FIXME(":stub\n");
2115 return TRUE;
2118 static const struct nls_update_font_list
2120 UINT ansi_cp, oem_cp;
2121 const char *oem, *fixed, *system;
2122 const char *courier, *serif, *small, *sserif;
2123 /* these are for font substitutes */
2124 const char *shelldlg, *tmsrmn;
2125 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2126 *helv_0, *tmsrmn_0;
2127 const struct subst
2129 const char *from, *to;
2130 } arial_0, courier_new_0, times_new_roman_0;
2131 } nls_update_font_list[] =
2133 /* Latin 1 (United States) */
2134 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2135 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2136 "Tahoma","Times New Roman",
2137 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2138 { 0 }, { 0 }, { 0 }
2140 /* Latin 1 (Multilingual) */
2141 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2142 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2143 "Tahoma","Times New Roman", /* FIXME unverified */
2144 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2145 { 0 }, { 0 }, { 0 }
2147 /* Eastern Europe */
2148 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2149 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2150 "Tahoma","Times New Roman", /* FIXME unverified */
2151 "Fixedsys,238", "System,238",
2152 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2153 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2154 { "Arial CE,0", "Arial,238" },
2155 { "Courier New CE,0", "Courier New,238" },
2156 { "Times New Roman CE,0", "Times New Roman,238" }
2158 /* Cyrillic */
2159 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2160 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2161 "Tahoma","Times New Roman", /* FIXME unverified */
2162 "Fixedsys,204", "System,204",
2163 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2164 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2165 { "Arial Cyr,0", "Arial,204" },
2166 { "Courier New Cyr,0", "Courier New,204" },
2167 { "Times New Roman Cyr,0", "Times New Roman,204" }
2169 /* Greek */
2170 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2171 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2172 "Tahoma","Times New Roman", /* FIXME unverified */
2173 "Fixedsys,161", "System,161",
2174 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2175 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2176 { "Arial Greek,0", "Arial,161" },
2177 { "Courier New Greek,0", "Courier New,161" },
2178 { "Times New Roman Greek,0", "Times New Roman,161" }
2180 /* Turkish */
2181 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2182 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2183 "Tahoma","Times New Roman", /* FIXME unverified */
2184 "Fixedsys,162", "System,162",
2185 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2186 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2187 { "Arial Tur,0", "Arial,162" },
2188 { "Courier New Tur,0", "Courier New,162" },
2189 { "Times New Roman Tur,0", "Times New Roman,162" }
2191 /* Hebrew */
2192 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2193 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2194 "Tahoma","Times New Roman", /* FIXME unverified */
2195 "Fixedsys,177", "System,177",
2196 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2197 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2198 { 0 }, { 0 }, { 0 }
2200 /* Arabic */
2201 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2202 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2203 "Tahoma","Times New Roman", /* FIXME unverified */
2204 "Fixedsys,178", "System,178",
2205 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2206 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2207 { 0 }, { 0 }, { 0 }
2209 /* Baltic */
2210 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2211 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2212 "Tahoma","Times New Roman", /* FIXME unverified */
2213 "Fixedsys,186", "System,186",
2214 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2215 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2216 { "Arial Baltic,0", "Arial,186" },
2217 { "Courier New Baltic,0", "Courier New,186" },
2218 { "Times New Roman Baltic,0", "Times New Roman,186" }
2220 /* Vietnamese */
2221 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2222 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2223 "Tahoma","Times New Roman", /* FIXME unverified */
2224 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2225 { 0 }, { 0 }, { 0 }
2227 /* Thai */
2228 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2229 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2230 "Tahoma","Times New Roman", /* FIXME unverified */
2231 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2232 { 0 }, { 0 }, { 0 }
2234 /* Japanese */
2235 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2236 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2237 "MS UI Gothic","MS Serif",
2238 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2239 { 0 }, { 0 }, { 0 }
2241 /* Chinese Simplified */
2242 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2243 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2244 "Tahoma", "Times New Roman", /* FIXME unverified */
2245 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2246 { 0 }, { 0 }, { 0 }
2248 /* Korean */
2249 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2250 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2251 "Gulim", "Batang",
2252 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2253 { 0 }, { 0 }, { 0 }
2255 /* Chinese Traditional */
2256 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2257 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2258 "PMingLiU", "MingLiU",
2259 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2260 { 0 }, { 0 }, { 0 }
2264 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2266 return ( ansi_cp == 932 /* CP932 for Japanese */
2267 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2268 || ansi_cp == 949 /* CP949 for Korean */
2269 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2272 static inline HKEY create_fonts_NT_registry_key(void)
2274 HKEY hkey = 0;
2276 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2277 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2278 return hkey;
2281 static inline HKEY create_fonts_9x_registry_key(void)
2283 HKEY hkey = 0;
2285 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2286 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2287 return hkey;
2290 static inline HKEY create_config_fonts_registry_key(void)
2292 HKEY hkey = 0;
2294 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2295 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2296 return hkey;
2299 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2301 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2302 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2303 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2304 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2307 static void set_value_key(HKEY hkey, const char *name, const char *value)
2309 if (value)
2310 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2311 else if (name)
2312 RegDeleteValueA(hkey, name);
2315 static void update_font_info(void)
2317 char buf[40], cpbuf[40];
2318 DWORD len, type;
2319 HKEY hkey = 0;
2320 UINT i, ansi_cp = 0, oem_cp = 0;
2321 BOOL done = FALSE;
2323 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2324 return;
2326 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2327 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2328 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2329 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2330 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2332 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2333 if (is_dbcs_ansi_cp(ansi_cp))
2334 use_default_fallback = TRUE;
2336 len = sizeof(buf);
2337 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2339 if (!strcmp( buf, cpbuf )) /* already set correctly */
2341 RegCloseKey(hkey);
2342 return;
2344 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2346 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2348 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2349 RegCloseKey(hkey);
2351 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2353 HKEY hkey;
2355 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2356 nls_update_font_list[i].oem_cp == oem_cp)
2358 hkey = create_config_fonts_registry_key();
2359 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2360 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2361 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2362 RegCloseKey(hkey);
2364 hkey = create_fonts_NT_registry_key();
2365 add_font_list(hkey, &nls_update_font_list[i]);
2366 RegCloseKey(hkey);
2368 hkey = create_fonts_9x_registry_key();
2369 add_font_list(hkey, &nls_update_font_list[i]);
2370 RegCloseKey(hkey);
2372 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2374 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2375 strlen(nls_update_font_list[i].shelldlg)+1);
2376 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2377 strlen(nls_update_font_list[i].tmsrmn)+1);
2379 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2380 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2381 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2382 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2383 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2384 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2385 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2386 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2388 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2389 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2390 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2392 RegCloseKey(hkey);
2394 done = TRUE;
2396 else
2398 /* Delete the FontSubstitutes from other locales */
2399 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2401 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2402 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2403 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2404 RegCloseKey(hkey);
2408 if (!done)
2409 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2413 static BOOL init_freetype(void)
2415 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2416 if(!ft_handle) {
2417 WINE_MESSAGE(
2418 "Wine cannot find the FreeType font library. To enable Wine to\n"
2419 "use TrueType fonts please install a version of FreeType greater than\n"
2420 "or equal to 2.0.5.\n"
2421 "http://www.freetype.org\n");
2422 return FALSE;
2425 #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;}
2427 LOAD_FUNCPTR(FT_Vector_Unit)
2428 LOAD_FUNCPTR(FT_Done_Face)
2429 LOAD_FUNCPTR(FT_Get_Char_Index)
2430 LOAD_FUNCPTR(FT_Get_Module)
2431 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2432 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2433 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2434 LOAD_FUNCPTR(FT_Init_FreeType)
2435 LOAD_FUNCPTR(FT_Load_Glyph)
2436 LOAD_FUNCPTR(FT_Matrix_Multiply)
2437 LOAD_FUNCPTR(FT_MulFix)
2438 LOAD_FUNCPTR(FT_New_Face)
2439 LOAD_FUNCPTR(FT_New_Memory_Face)
2440 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2441 LOAD_FUNCPTR(FT_Outline_Transform)
2442 LOAD_FUNCPTR(FT_Outline_Translate)
2443 LOAD_FUNCPTR(FT_Select_Charmap)
2444 LOAD_FUNCPTR(FT_Set_Charmap)
2445 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2446 LOAD_FUNCPTR(FT_Vector_Transform)
2448 #undef LOAD_FUNCPTR
2449 /* Don't warn if these ones are missing */
2450 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2451 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2452 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2453 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2454 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2455 #ifdef HAVE_FREETYPE_FTWINFNT_H
2456 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2457 #endif
2458 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2459 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2460 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2461 <= 2.0.3 has FT_Sqrt64 */
2462 goto sym_not_found;
2465 if(pFT_Init_FreeType(&library) != 0) {
2466 ERR("Can't init FreeType library\n");
2467 wine_dlclose(ft_handle, NULL, 0);
2468 ft_handle = NULL;
2469 return FALSE;
2471 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2472 if (pFT_Library_Version)
2473 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2475 if (FT_Version.major<=0)
2477 FT_Version.major=2;
2478 FT_Version.minor=0;
2479 FT_Version.patch=5;
2481 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2482 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2483 ((FT_Version.minor << 8) & 0x00ff00) |
2484 ((FT_Version.patch ) & 0x0000ff);
2486 return TRUE;
2488 sym_not_found:
2489 WINE_MESSAGE(
2490 "Wine cannot find certain functions that it needs inside the FreeType\n"
2491 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2492 "FreeType to at least version 2.0.5.\n"
2493 "http://www.freetype.org\n");
2494 wine_dlclose(ft_handle, NULL, 0);
2495 ft_handle = NULL;
2496 return FALSE;
2499 /*************************************************************
2500 * WineEngInit
2502 * Initialize FreeType library and create a list of available faces
2504 BOOL WineEngInit(void)
2506 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2507 static const WCHAR pathW[] = {'P','a','t','h',0};
2508 HKEY hkey;
2509 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2510 LPVOID data;
2511 WCHAR windowsdir[MAX_PATH];
2512 char *unixname;
2513 HANDLE font_mutex;
2514 const char *data_dir;
2516 TRACE("\n");
2518 /* update locale dependent font info in registry */
2519 update_font_info();
2521 if(!init_freetype()) return FALSE;
2523 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2524 ERR("Failed to create font mutex\n");
2525 return FALSE;
2527 WaitForSingleObject(font_mutex, INFINITE);
2529 delete_external_font_keys();
2531 /* load the system bitmap fonts */
2532 load_system_fonts();
2534 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2535 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2536 strcatW(windowsdir, fontsW);
2537 if((unixname = wine_get_unix_file_name(windowsdir)))
2539 ReadFontDir(unixname, FALSE);
2540 HeapFree(GetProcessHeap(), 0, unixname);
2543 /* load the system truetype fonts */
2544 data_dir = wine_get_data_dir();
2545 if (!data_dir) data_dir = wine_get_build_dir();
2546 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2547 strcpy(unixname, data_dir);
2548 strcat(unixname, "/fonts/");
2549 ReadFontDir(unixname, TRUE);
2550 HeapFree(GetProcessHeap(), 0, unixname);
2553 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2554 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2555 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2556 will skip these. */
2557 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2558 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2559 &hkey) == ERROR_SUCCESS) {
2560 LPWSTR valueW;
2561 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2562 &valuelen, &datalen, NULL, NULL);
2564 valuelen++; /* returned value doesn't include room for '\0' */
2565 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2566 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2567 if (valueW && data)
2569 dlen = datalen * sizeof(WCHAR);
2570 vlen = valuelen;
2571 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2572 &dlen) == ERROR_SUCCESS) {
2573 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2575 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2577 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2578 HeapFree(GetProcessHeap(), 0, unixname);
2581 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2583 WCHAR pathW[MAX_PATH];
2584 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2585 BOOL added = FALSE;
2587 sprintfW(pathW, fmtW, windowsdir, data);
2588 if((unixname = wine_get_unix_file_name(pathW)))
2590 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2591 HeapFree(GetProcessHeap(), 0, unixname);
2593 if (!added)
2594 load_font_from_data_dir(data);
2596 /* reset dlen and vlen */
2597 dlen = datalen;
2598 vlen = valuelen;
2601 HeapFree(GetProcessHeap(), 0, data);
2602 HeapFree(GetProcessHeap(), 0, valueW);
2603 RegCloseKey(hkey);
2606 load_fontconfig_fonts();
2608 /* then look in any directories that we've specified in the config file */
2609 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2610 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2612 DWORD len;
2613 LPWSTR valueW;
2614 LPSTR valueA, ptr;
2616 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2618 len += sizeof(WCHAR);
2619 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2620 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2622 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2623 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2624 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2625 TRACE( "got font path %s\n", debugstr_a(valueA) );
2626 ptr = valueA;
2627 while (ptr)
2629 LPSTR next = strchr( ptr, ':' );
2630 if (next) *next++ = 0;
2631 ReadFontDir( ptr, TRUE );
2632 ptr = next;
2634 HeapFree( GetProcessHeap(), 0, valueA );
2636 HeapFree( GetProcessHeap(), 0, valueW );
2638 RegCloseKey(hkey);
2641 DumpFontList();
2642 LoadSubstList();
2643 DumpSubstList();
2644 LoadReplaceList();
2645 update_reg_entries();
2647 init_system_links();
2649 ReleaseMutex(font_mutex);
2650 return TRUE;
2654 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2656 TT_OS2 *pOS2;
2657 TT_HoriHeader *pHori;
2659 LONG ppem;
2661 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2662 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2664 if(height == 0) height = 16;
2666 /* Calc. height of EM square:
2668 * For +ve lfHeight we have
2669 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2670 * Re-arranging gives:
2671 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2673 * For -ve lfHeight we have
2674 * |lfHeight| = ppem
2675 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2676 * with il = winAscent + winDescent - units_per_em]
2680 if(height > 0) {
2681 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2682 ppem = MulDiv(ft_face->units_per_EM, height,
2683 pHori->Ascender - pHori->Descender);
2684 else
2685 ppem = MulDiv(ft_face->units_per_EM, height,
2686 pOS2->usWinAscent + pOS2->usWinDescent);
2688 else
2689 ppem = -height;
2691 return ppem;
2694 static struct font_mapping *map_font_file( const char *name )
2696 struct font_mapping *mapping;
2697 struct stat st;
2698 int fd;
2700 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2701 if (fstat( fd, &st ) == -1) goto error;
2703 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2705 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2707 mapping->refcount++;
2708 close( fd );
2709 return mapping;
2712 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2713 goto error;
2715 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2716 close( fd );
2718 if (mapping->data == MAP_FAILED)
2720 HeapFree( GetProcessHeap(), 0, mapping );
2721 return NULL;
2723 mapping->refcount = 1;
2724 mapping->dev = st.st_dev;
2725 mapping->ino = st.st_ino;
2726 mapping->size = st.st_size;
2727 list_add_tail( &mappings_list, &mapping->entry );
2728 return mapping;
2730 error:
2731 close( fd );
2732 return NULL;
2735 static void unmap_font_file( struct font_mapping *mapping )
2737 if (!--mapping->refcount)
2739 list_remove( &mapping->entry );
2740 munmap( mapping->data, mapping->size );
2741 HeapFree( GetProcessHeap(), 0, mapping );
2745 static LONG load_VDMX(GdiFont*, LONG);
2747 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2749 FT_Error err;
2750 FT_Face ft_face;
2751 void *data_ptr;
2752 DWORD data_size;
2754 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2756 if (face->file)
2758 if (!(font->mapping = map_font_file( face->file )))
2760 WARN("failed to map %s\n", debugstr_a(face->file));
2761 return 0;
2763 data_ptr = font->mapping->data;
2764 data_size = font->mapping->size;
2766 else
2768 data_ptr = face->font_data_ptr;
2769 data_size = face->font_data_size;
2772 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2773 if(err) {
2774 ERR("FT_New_Face rets %d\n", err);
2775 return 0;
2778 /* set it here, as load_VDMX needs it */
2779 font->ft_face = ft_face;
2781 if(FT_IS_SCALABLE(ft_face)) {
2782 /* load the VDMX table if we have one */
2783 font->ppem = load_VDMX(font, height);
2784 if(font->ppem == 0)
2785 font->ppem = calc_ppem_for_height(ft_face, height);
2786 TRACE("height %d => ppem %d\n", height, font->ppem);
2788 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2789 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2790 } else {
2791 font->ppem = height;
2792 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2793 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2795 return ft_face;
2799 static int get_nearest_charset(Face *face, int *cp)
2801 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2802 a single face with the requested charset. The idea is to check if
2803 the selected font supports the current ANSI codepage, if it does
2804 return the corresponding charset, else return the first charset */
2806 CHARSETINFO csi;
2807 int acp = GetACP(), i;
2808 DWORD fs0;
2810 *cp = acp;
2811 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2812 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2813 return csi.ciCharset;
2815 for(i = 0; i < 32; i++) {
2816 fs0 = 1L << i;
2817 if(face->fs.fsCsb[0] & fs0) {
2818 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2819 *cp = csi.ciACP;
2820 return csi.ciCharset;
2822 else
2823 FIXME("TCI failing on %x\n", fs0);
2827 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2828 face->fs.fsCsb[0], face->file);
2829 *cp = acp;
2830 return DEFAULT_CHARSET;
2833 static GdiFont *alloc_font(void)
2835 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2836 ret->gmsize = 1;
2837 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2838 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2839 ret->potm = NULL;
2840 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2841 ret->total_kern_pairs = (DWORD)-1;
2842 ret->kern_pairs = NULL;
2843 list_init(&ret->hfontlist);
2844 list_init(&ret->child_fonts);
2845 return ret;
2848 static void free_font(GdiFont *font)
2850 struct list *cursor, *cursor2;
2851 int i;
2853 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2855 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2856 struct list *first_hfont;
2857 HFONTLIST *hfontlist;
2858 list_remove(cursor);
2859 if(child->font)
2861 first_hfont = list_head(&child->font->hfontlist);
2862 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2863 DeleteObject(hfontlist->hfont);
2864 HeapFree(GetProcessHeap(), 0, hfontlist);
2865 free_font(child->font);
2867 HeapFree(GetProcessHeap(), 0, child);
2870 if (font->ft_face) pFT_Done_Face(font->ft_face);
2871 if (font->mapping) unmap_font_file( font->mapping );
2872 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2873 HeapFree(GetProcessHeap(), 0, font->potm);
2874 HeapFree(GetProcessHeap(), 0, font->name);
2875 for (i = 0; i < font->gmsize; i++)
2876 HeapFree(GetProcessHeap(),0,font->gm[i]);
2877 HeapFree(GetProcessHeap(), 0, font->gm);
2878 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2879 HeapFree(GetProcessHeap(), 0, font);
2883 /*************************************************************
2884 * load_VDMX
2886 * load the vdmx entry for the specified height
2889 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2890 ( ( (FT_ULong)_x4 << 24 ) | \
2891 ( (FT_ULong)_x3 << 16 ) | \
2892 ( (FT_ULong)_x2 << 8 ) | \
2893 (FT_ULong)_x1 )
2895 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2897 typedef struct {
2898 BYTE bCharSet;
2899 BYTE xRatio;
2900 BYTE yStartRatio;
2901 BYTE yEndRatio;
2902 } Ratios;
2904 typedef struct {
2905 WORD recs;
2906 BYTE startsz;
2907 BYTE endsz;
2908 } VDMX_group;
2910 static LONG load_VDMX(GdiFont *font, LONG height)
2912 WORD hdr[3], tmp;
2913 VDMX_group group;
2914 BYTE devXRatio, devYRatio;
2915 USHORT numRecs, numRatios;
2916 DWORD result, offset = -1;
2917 LONG ppem = 0;
2918 int i;
2920 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2922 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2923 return ppem;
2925 /* FIXME: need the real device aspect ratio */
2926 devXRatio = 1;
2927 devYRatio = 1;
2929 numRecs = GET_BE_WORD(hdr[1]);
2930 numRatios = GET_BE_WORD(hdr[2]);
2932 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2933 for(i = 0; i < numRatios; i++) {
2934 Ratios ratio;
2936 offset = (3 * 2) + (i * sizeof(Ratios));
2937 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2938 offset = -1;
2940 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2942 if((ratio.xRatio == 0 &&
2943 ratio.yStartRatio == 0 &&
2944 ratio.yEndRatio == 0) ||
2945 (devXRatio == ratio.xRatio &&
2946 devYRatio >= ratio.yStartRatio &&
2947 devYRatio <= ratio.yEndRatio))
2949 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2950 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2951 offset = GET_BE_WORD(tmp);
2952 break;
2956 if(offset == -1) {
2957 FIXME("No suitable ratio found\n");
2958 return ppem;
2961 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2962 USHORT recs;
2963 BYTE startsz, endsz;
2964 WORD *vTable;
2966 recs = GET_BE_WORD(group.recs);
2967 startsz = group.startsz;
2968 endsz = group.endsz;
2970 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2972 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2973 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2974 if(result == GDI_ERROR) {
2975 FIXME("Failed to retrieve vTable\n");
2976 goto end;
2979 if(height > 0) {
2980 for(i = 0; i < recs; i++) {
2981 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2982 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2983 ppem = GET_BE_WORD(vTable[i * 3]);
2985 if(yMax + -yMin == height) {
2986 font->yMax = yMax;
2987 font->yMin = yMin;
2988 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2989 break;
2991 if(yMax + -yMin > height) {
2992 if(--i < 0) {
2993 ppem = 0;
2994 goto end; /* failed */
2996 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2997 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2998 ppem = GET_BE_WORD(vTable[i * 3]);
2999 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3000 break;
3003 if(!font->yMax) {
3004 ppem = 0;
3005 TRACE("ppem not found for height %d\n", height);
3007 } else {
3008 ppem = -height;
3009 if(ppem < startsz || ppem > endsz)
3010 goto end;
3012 for(i = 0; i < recs; i++) {
3013 USHORT yPelHeight;
3014 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3016 if(yPelHeight > ppem)
3017 break; /* failed */
3019 if(yPelHeight == ppem) {
3020 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3021 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3022 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3023 break;
3027 end:
3028 HeapFree(GetProcessHeap(), 0, vTable);
3031 return ppem;
3034 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3036 if(font->font_desc.hash != fd->hash) return TRUE;
3037 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3038 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3039 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3040 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3043 static void calc_hash(FONT_DESC *pfd)
3045 DWORD hash = 0, *ptr, two_chars;
3046 WORD *pwc;
3047 unsigned int i;
3049 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3050 hash ^= *ptr;
3051 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3052 hash ^= *ptr;
3053 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3054 two_chars = *ptr;
3055 pwc = (WCHAR *)&two_chars;
3056 if(!*pwc) break;
3057 *pwc = toupperW(*pwc);
3058 pwc++;
3059 *pwc = toupperW(*pwc);
3060 hash ^= two_chars;
3061 if(!*pwc) break;
3063 hash ^= !pfd->can_use_bitmap;
3064 pfd->hash = hash;
3065 return;
3068 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3070 GdiFont *ret;
3071 FONT_DESC fd;
3072 HFONTLIST *hflist;
3073 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3075 fd.lf = *plf;
3076 fd.matrix = *pmat;
3077 fd.can_use_bitmap = can_use_bitmap;
3078 calc_hash(&fd);
3080 /* try the in-use list */
3081 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3082 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3083 if(!fontcmp(ret, &fd)) {
3084 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3085 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3086 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3087 if(hflist->hfont == hfont)
3088 return ret;
3090 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3091 hflist->hfont = hfont;
3092 list_add_head(&ret->hfontlist, &hflist->entry);
3093 return ret;
3097 /* then the unused list */
3098 font_elem_ptr = list_head(&unused_gdi_font_list);
3099 while(font_elem_ptr) {
3100 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3101 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3102 if(!fontcmp(ret, &fd)) {
3103 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3104 assert(list_empty(&ret->hfontlist));
3105 TRACE("Found %p in unused list\n", ret);
3106 list_remove(&ret->entry);
3107 list_add_head(&gdi_font_list, &ret->entry);
3108 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3109 hflist->hfont = hfont;
3110 list_add_head(&ret->hfontlist, &hflist->entry);
3111 return ret;
3114 return NULL;
3117 static void add_to_cache(GdiFont *font)
3119 static DWORD cache_num = 1;
3121 font->cache_num = cache_num++;
3122 list_add_head(&gdi_font_list, &font->entry);
3125 /*************************************************************
3126 * create_child_font_list
3128 static BOOL create_child_font_list(GdiFont *font)
3130 BOOL ret = FALSE;
3131 SYSTEM_LINKS *font_link;
3132 CHILD_FONT *font_link_entry, *new_child;
3134 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3136 if(!strcmpW(font_link->font_name, font->name))
3138 TRACE("found entry in system list\n");
3139 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3141 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3142 new_child->face = font_link_entry->face;
3143 new_child->font = NULL;
3144 list_add_tail(&font->child_fonts, &new_child->entry);
3145 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3147 ret = TRUE;
3148 break;
3152 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3153 * Sans Serif. This is how asian windows get default fallbacks for fonts
3155 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3156 font->charset != OEM_CHARSET &&
3157 strcmpW(font->name,szDefaultFallbackLink) != 0)
3158 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3160 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3162 TRACE("found entry in default fallback list\n");
3163 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3165 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3166 new_child->face = font_link_entry->face;
3167 new_child->font = NULL;
3168 list_add_tail(&font->child_fonts, &new_child->entry);
3169 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3171 ret = TRUE;
3172 break;
3176 return ret;
3179 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3181 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3183 if (pFT_Set_Charmap)
3185 FT_Int i;
3186 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3188 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3190 for (i = 0; i < ft_face->num_charmaps; i++)
3192 if (ft_face->charmaps[i]->encoding == encoding)
3194 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3195 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3197 switch (ft_face->charmaps[i]->platform_id)
3199 default:
3200 cmap_def = ft_face->charmaps[i];
3201 break;
3202 case 0: /* Apple Unicode */
3203 cmap0 = ft_face->charmaps[i];
3204 break;
3205 case 1: /* Macintosh */
3206 cmap1 = ft_face->charmaps[i];
3207 break;
3208 case 2: /* ISO */
3209 cmap2 = ft_face->charmaps[i];
3210 break;
3211 case 3: /* Microsoft */
3212 cmap3 = ft_face->charmaps[i];
3213 break;
3217 if (cmap3) /* prefer Microsoft cmap table */
3218 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3219 else if (cmap1)
3220 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3221 else if (cmap2)
3222 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3223 else if (cmap0)
3224 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3225 else if (cmap_def)
3226 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3228 return ft_err == FT_Err_Ok;
3231 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3234 /*************************************************************
3235 * WineEngCreateFontInstance
3238 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3240 GdiFont *ret;
3241 Face *face, *best, *best_bitmap;
3242 Family *family, *last_resort_family;
3243 struct list *family_elem_ptr, *face_elem_ptr;
3244 INT height, width = 0;
3245 unsigned int score = 0, new_score;
3246 signed int diff = 0, newdiff;
3247 BOOL bd, it, can_use_bitmap;
3248 LOGFONTW lf;
3249 CHARSETINFO csi;
3250 HFONTLIST *hflist;
3251 FMAT2 dcmat;
3252 FontSubst *psub = NULL;
3254 EnterCriticalSection( &freetype_cs );
3256 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3258 struct list *first_hfont = list_head(&ret->hfontlist);
3259 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3260 if(hflist->hfont == hfont)
3262 LeaveCriticalSection( &freetype_cs );
3263 return ret;
3267 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3269 LeaveCriticalSection( &freetype_cs );
3270 return NULL;
3272 lf.lfWidth = abs(lf.lfWidth);
3274 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3276 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3277 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3278 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3279 lf.lfEscapement);
3281 if(dc->GraphicsMode == GM_ADVANCED)
3282 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3283 else
3285 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3286 font scaling abilities. */
3287 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3288 dcmat.eM21 = dcmat.eM12 = 0;
3291 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3292 dcmat.eM21, dcmat.eM22);
3294 /* check the cache first */
3295 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3296 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3297 LeaveCriticalSection( &freetype_cs );
3298 return ret;
3301 TRACE("not in cache\n");
3302 if(list_empty(&font_list)) /* No fonts installed */
3304 TRACE("No fonts installed\n");
3305 LeaveCriticalSection( &freetype_cs );
3306 return NULL;
3308 if(!have_installed_roman_font)
3310 TRACE("No roman font installed\n");
3311 LeaveCriticalSection( &freetype_cs );
3312 return NULL;
3315 ret = alloc_font();
3317 ret->font_desc.matrix = dcmat;
3318 ret->font_desc.lf = lf;
3319 ret->font_desc.can_use_bitmap = can_use_bitmap;
3320 calc_hash(&ret->font_desc);
3321 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3322 hflist->hfont = hfont;
3323 list_add_head(&ret->hfontlist, &hflist->entry);
3325 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3326 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3327 original value lfCharSet. Note this is a special case for
3328 Symbol and doesn't happen at least for "Wingdings*" */
3330 if(!strcmpiW(lf.lfFaceName, SymbolW))
3331 lf.lfCharSet = SYMBOL_CHARSET;
3333 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3334 switch(lf.lfCharSet) {
3335 case DEFAULT_CHARSET:
3336 csi.fs.fsCsb[0] = 0;
3337 break;
3338 default:
3339 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3340 csi.fs.fsCsb[0] = 0;
3341 break;
3345 family = NULL;
3346 if(lf.lfFaceName[0] != '\0') {
3347 SYSTEM_LINKS *font_link;
3348 CHILD_FONT *font_link_entry;
3349 LPWSTR FaceName = lf.lfFaceName;
3352 * Check for a leading '@' this signals that the font is being
3353 * requested in tategaki mode (vertical writing substitution) but
3354 * does not affect the fontface that is to be selected.
3356 if (lf.lfFaceName[0]=='@')
3357 FaceName = &lf.lfFaceName[1];
3359 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3361 if(psub) {
3362 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3363 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3364 if (psub->to.charset != -1)
3365 lf.lfCharSet = psub->to.charset;
3368 /* We want a match on name and charset or just name if
3369 charset was DEFAULT_CHARSET. If the latter then
3370 we fixup the returned charset later in get_nearest_charset
3371 where we'll either use the charset of the current ansi codepage
3372 or if that's unavailable the first charset that the font supports.
3374 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3375 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3376 if (!strcmpiW(family->FamilyName, FaceName) ||
3377 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3379 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3380 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3381 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3382 if(face->scalable || can_use_bitmap)
3383 goto found;
3389 * Try check the SystemLink list first for a replacement font.
3390 * We may find good replacements there.
3392 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3394 if(!strcmpiW(font_link->font_name, FaceName))
3396 TRACE("found entry in system list\n");
3397 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3399 face = font_link_entry->face;
3400 family = face->family;
3401 if(csi.fs.fsCsb[0] &
3402 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3404 if(face->scalable || can_use_bitmap)
3405 goto found;
3412 psub = NULL; /* substitution is no more relevant */
3414 /* If requested charset was DEFAULT_CHARSET then try using charset
3415 corresponding to the current ansi codepage */
3416 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3418 INT acp = GetACP();
3419 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3420 FIXME("TCI failed on codepage %d\n", acp);
3421 csi.fs.fsCsb[0] = 0;
3422 } else
3423 lf.lfCharSet = csi.ciCharset;
3426 /* Face families are in the top 4 bits of lfPitchAndFamily,
3427 so mask with 0xF0 before testing */
3429 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3430 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3431 strcpyW(lf.lfFaceName, defFixed);
3432 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3433 strcpyW(lf.lfFaceName, defSerif);
3434 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3435 strcpyW(lf.lfFaceName, defSans);
3436 else
3437 strcpyW(lf.lfFaceName, defSans);
3438 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3439 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3440 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3441 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3442 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3443 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3444 if(face->scalable || can_use_bitmap)
3445 goto found;
3450 last_resort_family = NULL;
3451 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3452 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3453 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3454 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3455 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3456 if(face->scalable)
3457 goto found;
3458 if(can_use_bitmap && !last_resort_family)
3459 last_resort_family = family;
3464 if(last_resort_family) {
3465 family = last_resort_family;
3466 csi.fs.fsCsb[0] = 0;
3467 goto found;
3470 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3471 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3472 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3473 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3474 if(face->scalable) {
3475 csi.fs.fsCsb[0] = 0;
3476 WARN("just using first face for now\n");
3477 goto found;
3479 if(can_use_bitmap && !last_resort_family)
3480 last_resort_family = family;
3483 if(!last_resort_family) {
3484 FIXME("can't find a single appropriate font - bailing\n");
3485 free_font(ret);
3486 LeaveCriticalSection( &freetype_cs );
3487 return NULL;
3490 WARN("could only find a bitmap font - this will probably look awful!\n");
3491 family = last_resort_family;
3492 csi.fs.fsCsb[0] = 0;
3494 found:
3495 it = lf.lfItalic ? 1 : 0;
3496 bd = lf.lfWeight > 550 ? 1 : 0;
3498 height = lf.lfHeight;
3500 face = best = best_bitmap = NULL;
3501 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3503 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3505 BOOL italic, bold;
3507 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3508 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3509 new_score = (italic ^ it) + (bold ^ bd);
3510 if(!best || new_score <= score)
3512 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3513 italic, bold, it, bd);
3514 score = new_score;
3515 best = face;
3516 if(best->scalable && score == 0) break;
3517 if(!best->scalable)
3519 if(height > 0)
3520 newdiff = height - (signed int)(best->size.height);
3521 else
3522 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3523 if(!best_bitmap || new_score < score ||
3524 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3526 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3527 diff = newdiff;
3528 best_bitmap = best;
3529 if(score == 0 && diff == 0) break;
3535 if(best)
3536 face = best->scalable ? best : best_bitmap;
3537 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3538 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3540 ret->fs = face->fs;
3542 if(csi.fs.fsCsb[0]) {
3543 ret->charset = lf.lfCharSet;
3544 ret->codepage = csi.ciACP;
3546 else
3547 ret->charset = get_nearest_charset(face, &ret->codepage);
3549 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3550 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3552 ret->aveWidth = height ? lf.lfWidth : 0;
3554 if(!face->scalable) {
3555 /* Windows uses integer scaling factors for bitmap fonts */
3556 INT scale, scaled_height;
3558 /* FIXME: rotation of bitmap fonts is ignored */
3559 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3560 if (ret->aveWidth)
3561 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3562 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3564 if (height != 0) height = diff;
3565 height += face->size.height;
3567 scale = (height + face->size.height - 1) / face->size.height;
3568 scaled_height = scale * face->size.height;
3569 /* XP allows not more than 10% deviation */
3570 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3571 ret->scale_y = scale;
3573 width = face->size.x_ppem >> 6;
3574 height = face->size.y_ppem >> 6;
3576 else
3577 ret->scale_y = 1.0;
3578 TRACE("font scale y: %f\n", ret->scale_y);
3580 ret->ft_face = OpenFontFace(ret, face, width, height);
3582 if (!ret->ft_face)
3584 free_font( ret );
3585 LeaveCriticalSection( &freetype_cs );
3586 return 0;
3589 ret->ntmFlags = face->ntmFlags;
3591 if (ret->charset == SYMBOL_CHARSET &&
3592 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3593 /* No ops */
3595 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3596 /* No ops */
3598 else {
3599 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3602 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3603 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3604 ret->underline = lf.lfUnderline ? 0xff : 0;
3605 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3606 create_child_font_list(ret);
3608 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3610 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3611 if (length != GDI_ERROR)
3613 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3614 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3615 TRACE("Loaded GSUB table of %i bytes\n",length);
3619 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3621 add_to_cache(ret);
3622 LeaveCriticalSection( &freetype_cs );
3623 return ret;
3626 static void dump_gdi_font_list(void)
3628 GdiFont *gdiFont;
3629 struct list *elem_ptr;
3631 TRACE("---------- gdiFont Cache ----------\n");
3632 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3633 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3634 TRACE("gdiFont=%p %s %d\n",
3635 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3638 TRACE("---------- Unused gdiFont Cache ----------\n");
3639 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3640 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3641 TRACE("gdiFont=%p %s %d\n",
3642 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3646 /*************************************************************
3647 * WineEngDestroyFontInstance
3649 * free the gdiFont associated with this handle
3652 BOOL WineEngDestroyFontInstance(HFONT handle)
3654 GdiFont *gdiFont;
3655 HFONTLIST *hflist;
3656 BOOL ret = FALSE;
3657 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3658 int i = 0;
3660 EnterCriticalSection( &freetype_cs );
3662 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3664 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3665 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3666 if(hflist->hfont == handle)
3668 TRACE("removing child font %p from child list\n", gdiFont);
3669 list_remove(&gdiFont->entry);
3670 LeaveCriticalSection( &freetype_cs );
3671 return TRUE;
3675 TRACE("destroying hfont=%p\n", handle);
3676 if(TRACE_ON(font))
3677 dump_gdi_font_list();
3679 font_elem_ptr = list_head(&gdi_font_list);
3680 while(font_elem_ptr) {
3681 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3682 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3684 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3685 while(hfontlist_elem_ptr) {
3686 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3687 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3688 if(hflist->hfont == handle) {
3689 list_remove(&hflist->entry);
3690 HeapFree(GetProcessHeap(), 0, hflist);
3691 ret = TRUE;
3694 if(list_empty(&gdiFont->hfontlist)) {
3695 TRACE("Moving to Unused list\n");
3696 list_remove(&gdiFont->entry);
3697 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3702 font_elem_ptr = list_head(&unused_gdi_font_list);
3703 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3704 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3705 while(font_elem_ptr) {
3706 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3707 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3708 TRACE("freeing %p\n", gdiFont);
3709 list_remove(&gdiFont->entry);
3710 free_font(gdiFont);
3712 LeaveCriticalSection( &freetype_cs );
3713 return ret;
3716 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3717 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3719 GdiFont *font;
3720 LONG width, height;
3722 if (face->cached_enum_data)
3724 TRACE("Cached\n");
3725 *pelf = face->cached_enum_data->elf;
3726 *pntm = face->cached_enum_data->ntm;
3727 *ptype = face->cached_enum_data->type;
3728 return;
3731 font = alloc_font();
3733 if(face->scalable) {
3734 height = -2048; /* 2048 is the most common em size */
3735 width = 0;
3736 } else {
3737 height = face->size.y_ppem >> 6;
3738 width = face->size.x_ppem >> 6;
3740 font->scale_y = 1.0;
3742 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3744 free_font(font);
3745 return;
3748 font->name = strdupW(face->family->FamilyName);
3749 font->ntmFlags = face->ntmFlags;
3751 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3753 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3755 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3757 lstrcpynW(pelf->elfLogFont.lfFaceName,
3758 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3759 LF_FACESIZE);
3760 lstrcpynW(pelf->elfFullName,
3761 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3762 LF_FULLFACESIZE);
3763 lstrcpynW(pelf->elfStyle,
3764 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3765 LF_FACESIZE);
3767 else
3769 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3771 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3773 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3774 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3775 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3778 pntm->ntmTm.ntmFlags = face->ntmFlags;
3779 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3780 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3781 pntm->ntmFontSig = face->fs;
3783 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3785 pelf->elfLogFont.lfEscapement = 0;
3786 pelf->elfLogFont.lfOrientation = 0;
3787 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3788 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3789 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3790 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3791 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3792 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3793 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3794 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3795 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3796 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3797 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3799 *ptype = 0;
3800 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3801 *ptype |= TRUETYPE_FONTTYPE;
3802 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3803 *ptype |= DEVICE_FONTTYPE;
3804 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3805 *ptype |= RASTER_FONTTYPE;
3807 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3808 if (face->cached_enum_data)
3810 face->cached_enum_data->elf = *pelf;
3811 face->cached_enum_data->ntm = *pntm;
3812 face->cached_enum_data->type = *ptype;
3815 free_font(font);
3818 /*************************************************************
3819 * WineEngEnumFonts
3822 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3824 Family *family;
3825 Face *face;
3826 struct list *family_elem_ptr, *face_elem_ptr;
3827 ENUMLOGFONTEXW elf;
3828 NEWTEXTMETRICEXW ntm;
3829 DWORD type;
3830 FONTSIGNATURE fs;
3831 CHARSETINFO csi;
3832 LOGFONTW lf;
3833 int i;
3835 if (!plf)
3837 lf.lfCharSet = DEFAULT_CHARSET;
3838 lf.lfPitchAndFamily = 0;
3839 lf.lfFaceName[0] = 0;
3840 plf = &lf;
3843 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3845 EnterCriticalSection( &freetype_cs );
3846 if(plf->lfFaceName[0]) {
3847 FontSubst *psub;
3848 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3850 if(psub) {
3851 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3852 debugstr_w(psub->to.name));
3853 lf = *plf;
3854 strcpyW(lf.lfFaceName, psub->to.name);
3855 plf = &lf;
3858 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3859 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3860 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3861 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3862 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3863 GetEnumStructs(face, &elf, &ntm, &type);
3864 for(i = 0; i < 32; i++) {
3865 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3866 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3867 strcpyW(elf.elfScript, OEM_DOSW);
3868 i = 32; /* break out of loop */
3869 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3870 continue;
3871 else {
3872 fs.fsCsb[0] = 1L << i;
3873 fs.fsCsb[1] = 0;
3874 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3875 TCI_SRCFONTSIG))
3876 csi.ciCharset = DEFAULT_CHARSET;
3877 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3878 if(csi.ciCharset != DEFAULT_CHARSET) {
3879 elf.elfLogFont.lfCharSet =
3880 ntm.ntmTm.tmCharSet = csi.ciCharset;
3881 if(ElfScriptsW[i])
3882 strcpyW(elf.elfScript, ElfScriptsW[i]);
3883 else
3884 FIXME("Unknown elfscript for bit %d\n", i);
3887 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3888 debugstr_w(elf.elfLogFont.lfFaceName),
3889 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3890 csi.ciCharset, type, debugstr_w(elf.elfScript),
3891 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3892 ntm.ntmTm.ntmFlags);
3893 /* release section before callback (FIXME) */
3894 LeaveCriticalSection( &freetype_cs );
3895 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3896 EnterCriticalSection( &freetype_cs );
3901 } else {
3902 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3903 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3904 face_elem_ptr = list_head(&family->faces);
3905 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3906 GetEnumStructs(face, &elf, &ntm, &type);
3907 for(i = 0; i < 32; i++) {
3908 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3909 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3910 strcpyW(elf.elfScript, OEM_DOSW);
3911 i = 32; /* break out of loop */
3912 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3913 continue;
3914 else {
3915 fs.fsCsb[0] = 1L << i;
3916 fs.fsCsb[1] = 0;
3917 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3918 TCI_SRCFONTSIG))
3919 csi.ciCharset = DEFAULT_CHARSET;
3920 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3921 if(csi.ciCharset != DEFAULT_CHARSET) {
3922 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3923 csi.ciCharset;
3924 if(ElfScriptsW[i])
3925 strcpyW(elf.elfScript, ElfScriptsW[i]);
3926 else
3927 FIXME("Unknown elfscript for bit %d\n", i);
3930 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3931 debugstr_w(elf.elfLogFont.lfFaceName),
3932 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3933 csi.ciCharset, type, debugstr_w(elf.elfScript),
3934 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3935 ntm.ntmTm.ntmFlags);
3936 /* release section before callback (FIXME) */
3937 LeaveCriticalSection( &freetype_cs );
3938 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3939 EnterCriticalSection( &freetype_cs );
3943 LeaveCriticalSection( &freetype_cs );
3944 return 1;
3947 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3949 pt->x.value = vec->x >> 6;
3950 pt->x.fract = (vec->x & 0x3f) << 10;
3951 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3952 pt->y.value = vec->y >> 6;
3953 pt->y.fract = (vec->y & 0x3f) << 10;
3954 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3955 return;
3958 /***************************************************
3959 * According to the MSDN documentation on WideCharToMultiByte,
3960 * certain codepages cannot set the default_used parameter.
3961 * This returns TRUE if the codepage can set that parameter, false else
3962 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3964 static BOOL codepage_sets_default_used(UINT codepage)
3966 switch (codepage)
3968 case CP_UTF7:
3969 case CP_UTF8:
3970 case CP_SYMBOL:
3971 return FALSE;
3972 default:
3973 return TRUE;
3978 * GSUB Table handling functions
3981 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3983 const GSUB_CoverageFormat1* cf1;
3985 cf1 = (GSUB_CoverageFormat1*)table;
3987 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3989 int count = GET_BE_WORD(cf1->GlyphCount);
3990 int i;
3991 TRACE("Coverage Format 1, %i glyphs\n",count);
3992 for (i = 0; i < count; i++)
3993 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3994 return i;
3995 return -1;
3997 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3999 const GSUB_CoverageFormat2* cf2;
4000 int i;
4001 int count;
4002 cf2 = (GSUB_CoverageFormat2*)cf1;
4004 count = GET_BE_WORD(cf2->RangeCount);
4005 TRACE("Coverage Format 2, %i ranges\n",count);
4006 for (i = 0; i < count; i++)
4008 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4009 return -1;
4010 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4011 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4013 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4014 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4017 return -1;
4019 else
4020 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4022 return -1;
4025 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4027 const GSUB_ScriptList *script;
4028 const GSUB_Script *deflt = NULL;
4029 int i;
4030 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4032 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4033 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4035 const GSUB_Script *scr;
4036 int offset;
4038 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4039 scr = (GSUB_Script*)((LPBYTE)script + offset);
4041 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4042 return scr;
4043 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4044 deflt = scr;
4046 return deflt;
4049 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4051 int i;
4052 int offset;
4053 const GSUB_LangSys *Lang;
4055 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4057 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4059 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4060 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4062 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4063 return Lang;
4065 offset = GET_BE_WORD(script->DefaultLangSys);
4066 if (offset)
4068 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4069 return Lang;
4071 return NULL;
4074 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4076 int i;
4077 const GSUB_FeatureList *feature;
4078 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4080 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4081 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4083 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4084 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4086 const GSUB_Feature *feat;
4087 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4088 return feat;
4091 return NULL;
4094 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4096 int i;
4097 int offset;
4098 const GSUB_LookupList *lookup;
4099 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4101 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4102 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4104 const GSUB_LookupTable *look;
4105 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4106 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4107 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4108 if (GET_BE_WORD(look->LookupType) != 1)
4109 FIXME("We only handle SubType 1\n");
4110 else
4112 int j;
4114 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4116 const GSUB_SingleSubstFormat1 *ssf1;
4117 offset = GET_BE_WORD(look->SubTable[j]);
4118 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4119 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4121 int offset = GET_BE_WORD(ssf1->Coverage);
4122 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4123 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4125 TRACE(" Glyph 0x%x ->",glyph);
4126 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4127 TRACE(" 0x%x\n",glyph);
4130 else
4132 const GSUB_SingleSubstFormat2 *ssf2;
4133 INT index;
4134 INT offset;
4136 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4137 offset = GET_BE_WORD(ssf1->Coverage);
4138 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4139 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4140 TRACE(" Coverage index %i\n",index);
4141 if (index != -1)
4143 TRACE(" Glyph is 0x%x ->",glyph);
4144 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4145 TRACE("0x%x\n",glyph);
4151 return glyph;
4154 static const char* get_opentype_script(const GdiFont *font)
4157 * I am not sure if this is the correct way to generate our script tag
4160 switch (font->charset)
4162 case ANSI_CHARSET: return "latn";
4163 case BALTIC_CHARSET: return "latn"; /* ?? */
4164 case CHINESEBIG5_CHARSET: return "hani";
4165 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4166 case GB2312_CHARSET: return "hani";
4167 case GREEK_CHARSET: return "grek";
4168 case HANGUL_CHARSET: return "hang";
4169 case RUSSIAN_CHARSET: return "cyrl";
4170 case SHIFTJIS_CHARSET: return "kana";
4171 case TURKISH_CHARSET: return "latn"; /* ?? */
4172 case VIETNAMESE_CHARSET: return "latn";
4173 case JOHAB_CHARSET: return "latn"; /* ?? */
4174 case ARABIC_CHARSET: return "arab";
4175 case HEBREW_CHARSET: return "hebr";
4176 case THAI_CHARSET: return "thai";
4177 default: return "latn";
4181 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4183 const GSUB_Header *header;
4184 const GSUB_Script *script;
4185 const GSUB_LangSys *language;
4186 const GSUB_Feature *feature;
4188 if (!font->GSUB_Table)
4189 return glyph;
4191 header = font->GSUB_Table;
4193 script = GSUB_get_script_table(header, get_opentype_script(font));
4194 if (!script)
4196 TRACE("Script not found\n");
4197 return glyph;
4199 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4200 if (!language)
4202 TRACE("Language not found\n");
4203 return glyph;
4205 feature = GSUB_get_feature(header, language, "vrt2");
4206 if (!feature)
4207 feature = GSUB_get_feature(header, language, "vert");
4208 if (!feature)
4210 TRACE("vrt2/vert feature not found\n");
4211 return glyph;
4213 return GSUB_apply_feature(header, feature, glyph);
4216 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4218 FT_UInt glyphId;
4220 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4221 WCHAR wc = (WCHAR)glyph;
4222 BOOL default_used;
4223 BOOL *default_used_pointer;
4224 FT_UInt ret;
4225 char buf;
4226 default_used_pointer = NULL;
4227 default_used = FALSE;
4228 if (codepage_sets_default_used(font->codepage))
4229 default_used_pointer = &default_used;
4230 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4231 ret = 0;
4232 else
4233 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4234 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4235 return get_GSUB_vert_glyph(font,ret);
4238 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4239 glyph = glyph + 0xf000;
4240 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4241 return get_GSUB_vert_glyph(font,glyphId);
4244 /*************************************************************
4245 * WineEngGetGlyphIndices
4248 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4249 LPWORD pgi, DWORD flags)
4251 int i;
4252 int default_char = -1;
4254 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4256 for(i = 0; i < count; i++)
4258 pgi[i] = get_glyph_index(font, lpstr[i]);
4259 if (pgi[i] == 0)
4261 if (default_char == -1)
4263 if (FT_IS_SFNT(font->ft_face))
4265 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4266 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4268 else
4270 TEXTMETRICW textm;
4271 WineEngGetTextMetrics(font, &textm);
4272 default_char = textm.tmDefaultChar;
4275 pgi[i] = default_char;
4278 return count;
4281 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4283 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4284 return !memcmp(matrix, &identity, sizeof(FMAT2));
4287 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4289 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4290 return !memcmp(matrix, &identity, sizeof(MAT2));
4293 /*************************************************************
4294 * WineEngGetGlyphOutline
4296 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4297 * except that the first parameter is the HWINEENGFONT of the font in
4298 * question rather than an HDC.
4301 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4302 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4303 const MAT2* lpmat)
4305 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4306 FT_Face ft_face = incoming_font->ft_face;
4307 GdiFont *font = incoming_font;
4308 FT_UInt glyph_index;
4309 DWORD width, height, pitch, needed = 0;
4310 FT_Bitmap ft_bitmap;
4311 FT_Error err;
4312 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4313 FT_Angle angle = 0;
4314 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4315 double widthRatio = 1.0;
4316 FT_Matrix transMat = identityMat;
4317 FT_Matrix transMatUnrotated;
4318 BOOL needsTransform = FALSE;
4319 BOOL tategaki = (font->GSUB_Table != NULL);
4320 UINT original_index;
4322 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4323 buflen, buf, lpmat);
4325 TRACE("font transform %f %f %f %f\n",
4326 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4327 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4329 EnterCriticalSection( &freetype_cs );
4331 if(format & GGO_GLYPH_INDEX) {
4332 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4333 original_index = glyph;
4334 format &= ~GGO_GLYPH_INDEX;
4335 } else {
4336 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4337 ft_face = font->ft_face;
4338 original_index = glyph_index;
4341 /* tategaki never appears to happen to lower glyph index */
4342 if (glyph_index < TATEGAKI_LOWER_BOUND )
4343 tategaki = FALSE;
4345 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4346 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4347 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4348 font->gmsize * sizeof(GM*));
4349 } else {
4350 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4351 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4353 *lpgm = FONT_GM(font,original_index)->gm;
4354 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4355 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4356 lpgm->gmCellIncX, lpgm->gmCellIncY);
4357 LeaveCriticalSection( &freetype_cs );
4358 return 1; /* FIXME */
4362 if (!font->gm[original_index / GM_BLOCK_SIZE])
4363 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4365 /* Scaling factor */
4366 if (font->aveWidth)
4368 TEXTMETRICW tm;
4370 WineEngGetTextMetrics(font, &tm);
4372 widthRatio = (double)font->aveWidth;
4373 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4375 else
4376 widthRatio = font->scale_y;
4378 /* Scaling transform */
4379 if (widthRatio != 1.0 || font->scale_y != 1.0)
4381 FT_Matrix scaleMat;
4382 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4383 scaleMat.xy = 0;
4384 scaleMat.yx = 0;
4385 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4387 pFT_Matrix_Multiply(&scaleMat, &transMat);
4388 needsTransform = TRUE;
4391 /* Slant transform */
4392 if (font->fake_italic) {
4393 FT_Matrix slantMat;
4395 slantMat.xx = (1 << 16);
4396 slantMat.xy = ((1 << 16) >> 2);
4397 slantMat.yx = 0;
4398 slantMat.yy = (1 << 16);
4399 pFT_Matrix_Multiply(&slantMat, &transMat);
4400 needsTransform = TRUE;
4403 /* Rotation transform */
4404 transMatUnrotated = transMat;
4405 if(font->orientation && !tategaki) {
4406 FT_Matrix rotationMat;
4407 FT_Vector vecAngle;
4408 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4409 pFT_Vector_Unit(&vecAngle, angle);
4410 rotationMat.xx = vecAngle.x;
4411 rotationMat.xy = -vecAngle.y;
4412 rotationMat.yx = -rotationMat.xy;
4413 rotationMat.yy = rotationMat.xx;
4415 pFT_Matrix_Multiply(&rotationMat, &transMat);
4416 needsTransform = TRUE;
4419 /* World transform */
4420 if (!is_identity_FMAT2(&font->font_desc.matrix))
4422 FT_Matrix worldMat;
4423 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4424 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4425 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4426 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4427 pFT_Matrix_Multiply(&worldMat, &transMat);
4428 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4429 needsTransform = TRUE;
4432 /* Extra transformation specified by caller */
4433 if (lpmat && !is_identity_MAT2(lpmat))
4435 FT_Matrix extraMat;
4436 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4437 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4438 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4439 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4440 pFT_Matrix_Multiply(&extraMat, &transMat);
4441 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4442 needsTransform = TRUE;
4445 if (needsTransform || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP))
4446 load_flags |= FT_LOAD_NO_BITMAP;
4448 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4450 if(err) {
4451 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4452 LeaveCriticalSection( &freetype_cs );
4453 return GDI_ERROR;
4456 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4457 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4459 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4460 lsb = left >> 6;
4461 bbx = (right - left) >> 6;
4463 if(!needsTransform) {
4464 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4465 bottom = (ft_face->glyph->metrics.horiBearingY -
4466 ft_face->glyph->metrics.height) & -64;
4467 lpgm->gmCellIncX = adv;
4468 lpgm->gmCellIncY = 0;
4469 } else {
4470 INT xc, yc;
4471 FT_Vector vec;
4472 for(xc = 0; xc < 2; xc++) {
4473 for(yc = 0; yc < 2; yc++) {
4474 vec.x = (ft_face->glyph->metrics.horiBearingX +
4475 xc * ft_face->glyph->metrics.width);
4476 vec.y = ft_face->glyph->metrics.horiBearingY -
4477 yc * ft_face->glyph->metrics.height;
4478 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4479 pFT_Vector_Transform(&vec, &transMat);
4480 if(xc == 0 && yc == 0) {
4481 left = right = vec.x;
4482 top = bottom = vec.y;
4483 } else {
4484 if(vec.x < left) left = vec.x;
4485 else if(vec.x > right) right = vec.x;
4486 if(vec.y < bottom) bottom = vec.y;
4487 else if(vec.y > top) top = vec.y;
4491 left = left & -64;
4492 right = (right + 63) & -64;
4493 bottom = bottom & -64;
4494 top = (top + 63) & -64;
4496 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4497 vec.x = ft_face->glyph->metrics.horiAdvance;
4498 vec.y = 0;
4499 pFT_Vector_Transform(&vec, &transMat);
4500 lpgm->gmCellIncX = (vec.x+63) >> 6;
4501 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4503 vec.x = ft_face->glyph->metrics.horiAdvance;
4504 vec.y = 0;
4505 pFT_Vector_Transform(&vec, &transMatUnrotated);
4506 adv = (vec.x+63) >> 6;
4508 lpgm->gmBlackBoxX = (right - left) >> 6;
4509 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4510 lpgm->gmptGlyphOrigin.x = left >> 6;
4511 lpgm->gmptGlyphOrigin.y = top >> 6;
4513 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4514 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4515 lpgm->gmCellIncX, lpgm->gmCellIncY);
4517 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4518 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4520 FONT_GM(font,original_index)->gm = *lpgm;
4521 FONT_GM(font,original_index)->adv = adv;
4522 FONT_GM(font,original_index)->lsb = lsb;
4523 FONT_GM(font,original_index)->bbx = bbx;
4524 FONT_GM(font,original_index)->init = TRUE;
4527 if(format == GGO_METRICS)
4529 LeaveCriticalSection( &freetype_cs );
4530 return 1; /* FIXME */
4533 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4534 TRACE("loaded a bitmap\n");
4535 LeaveCriticalSection( &freetype_cs );
4536 return GDI_ERROR;
4539 switch(format) {
4540 case GGO_BITMAP:
4541 width = lpgm->gmBlackBoxX;
4542 height = lpgm->gmBlackBoxY;
4543 pitch = ((width + 31) >> 5) << 2;
4544 needed = pitch * height;
4546 if(!buf || !buflen) break;
4548 switch(ft_face->glyph->format) {
4549 case ft_glyph_format_bitmap:
4551 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4552 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4553 INT h = ft_face->glyph->bitmap.rows;
4554 while(h--) {
4555 memcpy(dst, src, w);
4556 src += ft_face->glyph->bitmap.pitch;
4557 dst += pitch;
4559 break;
4562 case ft_glyph_format_outline:
4563 ft_bitmap.width = width;
4564 ft_bitmap.rows = height;
4565 ft_bitmap.pitch = pitch;
4566 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4567 ft_bitmap.buffer = buf;
4569 if(needsTransform) {
4570 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4573 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4575 /* Note: FreeType will only set 'black' bits for us. */
4576 memset(buf, 0, needed);
4577 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4578 break;
4580 default:
4581 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4582 LeaveCriticalSection( &freetype_cs );
4583 return GDI_ERROR;
4585 break;
4587 case GGO_GRAY2_BITMAP:
4588 case GGO_GRAY4_BITMAP:
4589 case GGO_GRAY8_BITMAP:
4590 case WINE_GGO_GRAY16_BITMAP:
4592 unsigned int mult, row, col;
4593 BYTE *start, *ptr;
4595 width = lpgm->gmBlackBoxX;
4596 height = lpgm->gmBlackBoxY;
4597 pitch = (width + 3) / 4 * 4;
4598 needed = pitch * height;
4600 if(!buf || !buflen) break;
4602 switch(ft_face->glyph->format) {
4603 case ft_glyph_format_bitmap:
4605 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4606 INT h = ft_face->glyph->bitmap.rows;
4607 INT x;
4608 while(h--) {
4609 for(x = 0; x < pitch; x++)
4611 if(x < ft_face->glyph->bitmap.width)
4612 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4613 else
4614 dst[x] = 0;
4616 src += ft_face->glyph->bitmap.pitch;
4617 dst += pitch;
4619 LeaveCriticalSection( &freetype_cs );
4620 return needed;
4622 case ft_glyph_format_outline:
4624 ft_bitmap.width = width;
4625 ft_bitmap.rows = height;
4626 ft_bitmap.pitch = pitch;
4627 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4628 ft_bitmap.buffer = buf;
4630 if(needsTransform)
4631 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4633 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4635 memset(ft_bitmap.buffer, 0, buflen);
4637 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4639 if(format == GGO_GRAY2_BITMAP)
4640 mult = 4;
4641 else if(format == GGO_GRAY4_BITMAP)
4642 mult = 16;
4643 else if(format == GGO_GRAY8_BITMAP)
4644 mult = 64;
4645 else /* format == WINE_GGO_GRAY16_BITMAP */
4647 LeaveCriticalSection( &freetype_cs );
4648 return needed;
4650 break;
4652 default:
4653 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4654 LeaveCriticalSection( &freetype_cs );
4655 return GDI_ERROR;
4658 start = buf;
4659 for(row = 0; row < height; row++) {
4660 ptr = start;
4661 for(col = 0; col < width; col++, ptr++) {
4662 *ptr = (((int)*ptr) * mult + 128) / 256;
4664 start += pitch;
4666 break;
4669 case GGO_NATIVE:
4671 int contour, point = 0, first_pt;
4672 FT_Outline *outline = &ft_face->glyph->outline;
4673 TTPOLYGONHEADER *pph;
4674 TTPOLYCURVE *ppc;
4675 DWORD pph_start, cpfx, type;
4677 if(buflen == 0) buf = NULL;
4679 if (needsTransform && buf) {
4680 pFT_Outline_Transform(outline, &transMat);
4683 for(contour = 0; contour < outline->n_contours; contour++) {
4684 pph_start = needed;
4685 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4686 first_pt = point;
4687 if(buf) {
4688 pph->dwType = TT_POLYGON_TYPE;
4689 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4691 needed += sizeof(*pph);
4692 point++;
4693 while(point <= outline->contours[contour]) {
4694 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4695 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4696 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4697 cpfx = 0;
4698 do {
4699 if(buf)
4700 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4701 cpfx++;
4702 point++;
4703 } while(point <= outline->contours[contour] &&
4704 (outline->tags[point] & FT_Curve_Tag_On) ==
4705 (outline->tags[point-1] & FT_Curve_Tag_On));
4706 /* At the end of a contour Windows adds the start point, but
4707 only for Beziers */
4708 if(point > outline->contours[contour] &&
4709 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4710 if(buf)
4711 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4712 cpfx++;
4713 } else if(point <= outline->contours[contour] &&
4714 outline->tags[point] & FT_Curve_Tag_On) {
4715 /* add closing pt for bezier */
4716 if(buf)
4717 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4718 cpfx++;
4719 point++;
4721 if(buf) {
4722 ppc->wType = type;
4723 ppc->cpfx = cpfx;
4725 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4727 if(buf)
4728 pph->cb = needed - pph_start;
4730 break;
4732 case GGO_BEZIER:
4734 /* Convert the quadratic Beziers to cubic Beziers.
4735 The parametric eqn for a cubic Bezier is, from PLRM:
4736 r(t) = at^3 + bt^2 + ct + r0
4737 with the control points:
4738 r1 = r0 + c/3
4739 r2 = r1 + (c + b)/3
4740 r3 = r0 + c + b + a
4742 A quadratic Beizer has the form:
4743 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4745 So equating powers of t leads to:
4746 r1 = 2/3 p1 + 1/3 p0
4747 r2 = 2/3 p1 + 1/3 p2
4748 and of course r0 = p0, r3 = p2
4751 int contour, point = 0, first_pt;
4752 FT_Outline *outline = &ft_face->glyph->outline;
4753 TTPOLYGONHEADER *pph;
4754 TTPOLYCURVE *ppc;
4755 DWORD pph_start, cpfx, type;
4756 FT_Vector cubic_control[4];
4757 if(buflen == 0) buf = NULL;
4759 if (needsTransform && buf) {
4760 pFT_Outline_Transform(outline, &transMat);
4763 for(contour = 0; contour < outline->n_contours; contour++) {
4764 pph_start = needed;
4765 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4766 first_pt = point;
4767 if(buf) {
4768 pph->dwType = TT_POLYGON_TYPE;
4769 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4771 needed += sizeof(*pph);
4772 point++;
4773 while(point <= outline->contours[contour]) {
4774 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4775 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4776 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4777 cpfx = 0;
4778 do {
4779 if(type == TT_PRIM_LINE) {
4780 if(buf)
4781 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4782 cpfx++;
4783 point++;
4784 } else {
4785 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4786 so cpfx = 3n */
4788 /* FIXME: Possible optimization in endpoint calculation
4789 if there are two consecutive curves */
4790 cubic_control[0] = outline->points[point-1];
4791 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4792 cubic_control[0].x += outline->points[point].x + 1;
4793 cubic_control[0].y += outline->points[point].y + 1;
4794 cubic_control[0].x >>= 1;
4795 cubic_control[0].y >>= 1;
4797 if(point+1 > outline->contours[contour])
4798 cubic_control[3] = outline->points[first_pt];
4799 else {
4800 cubic_control[3] = outline->points[point+1];
4801 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4802 cubic_control[3].x += outline->points[point].x + 1;
4803 cubic_control[3].y += outline->points[point].y + 1;
4804 cubic_control[3].x >>= 1;
4805 cubic_control[3].y >>= 1;
4808 /* r1 = 1/3 p0 + 2/3 p1
4809 r2 = 1/3 p2 + 2/3 p1 */
4810 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4811 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4812 cubic_control[2] = cubic_control[1];
4813 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4814 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4815 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4816 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4817 if(buf) {
4818 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4819 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4820 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4822 cpfx += 3;
4823 point++;
4825 } while(point <= outline->contours[contour] &&
4826 (outline->tags[point] & FT_Curve_Tag_On) ==
4827 (outline->tags[point-1] & FT_Curve_Tag_On));
4828 /* At the end of a contour Windows adds the start point,
4829 but only for Beziers and we've already done that.
4831 if(point <= outline->contours[contour] &&
4832 outline->tags[point] & FT_Curve_Tag_On) {
4833 /* This is the closing pt of a bezier, but we've already
4834 added it, so just inc point and carry on */
4835 point++;
4837 if(buf) {
4838 ppc->wType = type;
4839 ppc->cpfx = cpfx;
4841 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4843 if(buf)
4844 pph->cb = needed - pph_start;
4846 break;
4849 default:
4850 FIXME("Unsupported format %d\n", format);
4851 LeaveCriticalSection( &freetype_cs );
4852 return GDI_ERROR;
4854 LeaveCriticalSection( &freetype_cs );
4855 return needed;
4858 static BOOL get_bitmap_text_metrics(GdiFont *font)
4860 FT_Face ft_face = font->ft_face;
4861 #ifdef HAVE_FREETYPE_FTWINFNT_H
4862 FT_WinFNT_HeaderRec winfnt_header;
4863 #endif
4864 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4865 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4866 font->potm->otmSize = size;
4868 #define TM font->potm->otmTextMetrics
4869 #ifdef HAVE_FREETYPE_FTWINFNT_H
4870 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4872 TM.tmHeight = winfnt_header.pixel_height;
4873 TM.tmAscent = winfnt_header.ascent;
4874 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4875 TM.tmInternalLeading = winfnt_header.internal_leading;
4876 TM.tmExternalLeading = winfnt_header.external_leading;
4877 TM.tmAveCharWidth = winfnt_header.avg_width;
4878 TM.tmMaxCharWidth = winfnt_header.max_width;
4879 TM.tmWeight = winfnt_header.weight;
4880 TM.tmOverhang = 0;
4881 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4882 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4883 TM.tmFirstChar = winfnt_header.first_char;
4884 TM.tmLastChar = winfnt_header.last_char;
4885 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4886 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4887 TM.tmItalic = winfnt_header.italic;
4888 TM.tmUnderlined = font->underline;
4889 TM.tmStruckOut = font->strikeout;
4890 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4891 TM.tmCharSet = winfnt_header.charset;
4893 else
4894 #endif
4896 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4897 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4898 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4899 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4900 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4901 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4902 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4903 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4904 TM.tmOverhang = 0;
4905 TM.tmDigitizedAspectX = 96; /* FIXME */
4906 TM.tmDigitizedAspectY = 96; /* FIXME */
4907 TM.tmFirstChar = 1;
4908 TM.tmLastChar = 255;
4909 TM.tmDefaultChar = 32;
4910 TM.tmBreakChar = 32;
4911 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4912 TM.tmUnderlined = font->underline;
4913 TM.tmStruckOut = font->strikeout;
4914 /* NB inverted meaning of TMPF_FIXED_PITCH */
4915 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4916 TM.tmCharSet = font->charset;
4918 #undef TM
4920 return TRUE;
4924 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4926 double scale_x, scale_y;
4928 if (font->aveWidth)
4930 scale_x = (double)font->aveWidth;
4931 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4933 else
4934 scale_x = font->scale_y;
4936 scale_x *= fabs(font->font_desc.matrix.eM11);
4937 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4939 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4940 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4942 SCALE_Y(ptm->tmHeight);
4943 SCALE_Y(ptm->tmAscent);
4944 SCALE_Y(ptm->tmDescent);
4945 SCALE_Y(ptm->tmInternalLeading);
4946 SCALE_Y(ptm->tmExternalLeading);
4947 SCALE_Y(ptm->tmOverhang);
4949 SCALE_X(ptm->tmAveCharWidth);
4950 SCALE_X(ptm->tmMaxCharWidth);
4952 #undef SCALE_X
4953 #undef SCALE_Y
4956 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4958 double scale_x, scale_y;
4960 if (font->aveWidth)
4962 scale_x = (double)font->aveWidth;
4963 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4965 else
4966 scale_x = font->scale_y;
4968 scale_x *= fabs(font->font_desc.matrix.eM11);
4969 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4971 scale_font_metrics(font, &potm->otmTextMetrics);
4973 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4974 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4976 SCALE_Y(potm->otmAscent);
4977 SCALE_Y(potm->otmDescent);
4978 SCALE_Y(potm->otmLineGap);
4979 SCALE_Y(potm->otmsCapEmHeight);
4980 SCALE_Y(potm->otmsXHeight);
4981 SCALE_Y(potm->otmrcFontBox.top);
4982 SCALE_Y(potm->otmrcFontBox.bottom);
4983 SCALE_X(potm->otmrcFontBox.left);
4984 SCALE_X(potm->otmrcFontBox.right);
4985 SCALE_Y(potm->otmMacAscent);
4986 SCALE_Y(potm->otmMacDescent);
4987 SCALE_Y(potm->otmMacLineGap);
4988 SCALE_X(potm->otmptSubscriptSize.x);
4989 SCALE_Y(potm->otmptSubscriptSize.y);
4990 SCALE_X(potm->otmptSubscriptOffset.x);
4991 SCALE_Y(potm->otmptSubscriptOffset.y);
4992 SCALE_X(potm->otmptSuperscriptSize.x);
4993 SCALE_Y(potm->otmptSuperscriptSize.y);
4994 SCALE_X(potm->otmptSuperscriptOffset.x);
4995 SCALE_Y(potm->otmptSuperscriptOffset.y);
4996 SCALE_Y(potm->otmsStrikeoutSize);
4997 SCALE_Y(potm->otmsStrikeoutPosition);
4998 SCALE_Y(potm->otmsUnderscoreSize);
4999 SCALE_Y(potm->otmsUnderscorePosition);
5001 #undef SCALE_X
5002 #undef SCALE_Y
5005 /*************************************************************
5006 * WineEngGetTextMetrics
5009 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5011 EnterCriticalSection( &freetype_cs );
5012 if(!font->potm) {
5013 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5014 if(!get_bitmap_text_metrics(font))
5016 LeaveCriticalSection( &freetype_cs );
5017 return FALSE;
5020 if(!font->potm)
5022 LeaveCriticalSection( &freetype_cs );
5023 return FALSE;
5025 *ptm = font->potm->otmTextMetrics;
5026 scale_font_metrics(font, ptm);
5027 LeaveCriticalSection( &freetype_cs );
5028 return TRUE;
5032 /*************************************************************
5033 * WineEngGetOutlineTextMetrics
5036 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5037 OUTLINETEXTMETRICW *potm)
5039 FT_Face ft_face = font->ft_face;
5040 UINT needed, lenfam, lensty, ret;
5041 TT_OS2 *pOS2;
5042 TT_HoriHeader *pHori;
5043 TT_Postscript *pPost;
5044 FT_Fixed x_scale, y_scale;
5045 WCHAR *family_nameW, *style_nameW;
5046 static const WCHAR spaceW[] = {' ', '\0'};
5047 char *cp;
5048 INT ascent, descent;
5050 TRACE("font=%p\n", font);
5052 if(!FT_IS_SCALABLE(ft_face))
5053 return 0;
5055 EnterCriticalSection( &freetype_cs );
5057 if(font->potm) {
5058 if(cbSize >= font->potm->otmSize)
5060 memcpy(potm, font->potm, font->potm->otmSize);
5061 scale_outline_font_metrics(font, potm);
5063 LeaveCriticalSection( &freetype_cs );
5064 return font->potm->otmSize;
5068 needed = sizeof(*potm);
5070 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5071 family_nameW = strdupW(font->name);
5073 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5074 * sizeof(WCHAR);
5075 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5076 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5077 style_nameW, lensty/sizeof(WCHAR));
5079 /* These names should be read from the TT name table */
5081 /* length of otmpFamilyName */
5082 needed += lenfam;
5084 /* length of otmpFaceName */
5085 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5086 needed += lenfam; /* just the family name */
5087 } else {
5088 needed += lenfam + lensty; /* family + " " + style */
5091 /* length of otmpStyleName */
5092 needed += lensty;
5094 /* length of otmpFullName */
5095 needed += lenfam + lensty;
5098 x_scale = ft_face->size->metrics.x_scale;
5099 y_scale = ft_face->size->metrics.y_scale;
5101 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5102 if(!pOS2) {
5103 FIXME("Can't find OS/2 table - not TT font?\n");
5104 ret = 0;
5105 goto end;
5108 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5109 if(!pHori) {
5110 FIXME("Can't find HHEA table - not TT font?\n");
5111 ret = 0;
5112 goto end;
5115 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5117 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",
5118 pOS2->usWinAscent, pOS2->usWinDescent,
5119 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5120 ft_face->ascender, ft_face->descender, ft_face->height,
5121 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5122 ft_face->bbox.yMax, ft_face->bbox.yMin);
5124 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5125 font->potm->otmSize = needed;
5127 #define TM font->potm->otmTextMetrics
5129 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5130 ascent = pHori->Ascender;
5131 descent = -pHori->Descender;
5132 } else {
5133 ascent = pOS2->usWinAscent;
5134 descent = pOS2->usWinDescent;
5137 if(font->yMax) {
5138 TM.tmAscent = font->yMax;
5139 TM.tmDescent = -font->yMin;
5140 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5141 } else {
5142 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5143 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5144 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5145 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5148 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5150 /* MSDN says:
5151 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5153 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5154 ((ascent + descent) -
5155 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5157 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5158 if (TM.tmAveCharWidth == 0) {
5159 TM.tmAveCharWidth = 1;
5161 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5162 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
5163 TM.tmOverhang = 0;
5164 TM.tmDigitizedAspectX = 300;
5165 TM.tmDigitizedAspectY = 300;
5166 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5167 * symbol range to 0 - f0ff
5169 if (font->charset == SYMBOL_CHARSET)
5171 TM.tmFirstChar = 0;
5172 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5174 else
5176 TM.tmFirstChar = pOS2->usFirstCharIndex;
5177 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5179 TM.tmLastChar = pOS2->usLastCharIndex;
5180 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5181 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5182 TM.tmUnderlined = font->underline;
5183 TM.tmStruckOut = font->strikeout;
5185 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5186 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5187 (pOS2->version == 0xFFFFU ||
5188 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5189 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5190 else
5191 TM.tmPitchAndFamily = 0;
5193 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5194 case PAN_FAMILY_SCRIPT:
5195 TM.tmPitchAndFamily |= FF_SCRIPT;
5196 break;
5197 case PAN_FAMILY_DECORATIVE:
5198 case PAN_FAMILY_PICTORIAL:
5199 TM.tmPitchAndFamily |= FF_DECORATIVE;
5200 break;
5201 case PAN_FAMILY_TEXT_DISPLAY:
5202 if(TM.tmPitchAndFamily == 0) /* fixed */
5203 TM.tmPitchAndFamily = FF_MODERN;
5204 else {
5205 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5206 case PAN_SERIF_NORMAL_SANS:
5207 case PAN_SERIF_OBTUSE_SANS:
5208 case PAN_SERIF_PERP_SANS:
5209 TM.tmPitchAndFamily |= FF_SWISS;
5210 break;
5211 default:
5212 TM.tmPitchAndFamily |= FF_ROMAN;
5215 break;
5216 default:
5217 TM.tmPitchAndFamily |= FF_DONTCARE;
5220 if(FT_IS_SCALABLE(ft_face))
5221 TM.tmPitchAndFamily |= TMPF_VECTOR;
5223 if(FT_IS_SFNT(ft_face))
5225 if (font->ntmFlags & NTM_PS_OPENTYPE)
5226 TM.tmPitchAndFamily |= TMPF_DEVICE;
5227 else
5228 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5231 TM.tmCharSet = font->charset;
5233 font->potm->otmFiller = 0;
5234 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5235 font->potm->otmfsSelection = pOS2->fsSelection;
5236 font->potm->otmfsType = pOS2->fsType;
5237 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5238 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5239 font->potm->otmItalicAngle = 0; /* POST table */
5240 font->potm->otmEMSquare = ft_face->units_per_EM;
5241 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5242 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5243 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5244 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5245 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5246 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5247 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5248 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5249 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5250 font->potm->otmMacAscent = TM.tmAscent;
5251 font->potm->otmMacDescent = -TM.tmDescent;
5252 font->potm->otmMacLineGap = font->potm->otmLineGap;
5253 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5254 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5255 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5256 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5257 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5258 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5259 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5260 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5261 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5262 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5263 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5264 if(!pPost) {
5265 font->potm->otmsUnderscoreSize = 0;
5266 font->potm->otmsUnderscorePosition = 0;
5267 } else {
5268 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5269 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5271 #undef TM
5273 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5274 cp = (char*)font->potm + sizeof(*font->potm);
5275 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5276 strcpyW((WCHAR*)cp, family_nameW);
5277 cp += lenfam;
5278 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5279 strcpyW((WCHAR*)cp, style_nameW);
5280 cp += lensty;
5281 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5282 strcpyW((WCHAR*)cp, family_nameW);
5283 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5284 strcatW((WCHAR*)cp, spaceW);
5285 strcatW((WCHAR*)cp, style_nameW);
5286 cp += lenfam + lensty;
5287 } else
5288 cp += lenfam;
5289 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5290 strcpyW((WCHAR*)cp, family_nameW);
5291 strcatW((WCHAR*)cp, spaceW);
5292 strcatW((WCHAR*)cp, style_nameW);
5293 ret = needed;
5295 if(potm && needed <= cbSize)
5297 memcpy(potm, font->potm, font->potm->otmSize);
5298 scale_outline_font_metrics(font, potm);
5301 end:
5302 HeapFree(GetProcessHeap(), 0, style_nameW);
5303 HeapFree(GetProcessHeap(), 0, family_nameW);
5305 LeaveCriticalSection( &freetype_cs );
5306 return ret;
5309 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5311 HFONTLIST *hfontlist;
5312 child->font = alloc_font();
5313 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5314 if(!child->font->ft_face)
5316 free_font(child->font);
5317 child->font = NULL;
5318 return FALSE;
5321 child->font->ntmFlags = child->face->ntmFlags;
5322 child->font->orientation = font->orientation;
5323 child->font->scale_y = font->scale_y;
5324 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5325 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5326 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5327 child->font->base_font = font;
5328 list_add_head(&child_font_list, &child->font->entry);
5329 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5330 return TRUE;
5333 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5335 FT_UInt g;
5336 CHILD_FONT *child_font;
5338 if(font->base_font)
5339 font = font->base_font;
5341 *linked_font = font;
5343 if((*glyph = get_glyph_index(font, c)))
5344 return TRUE;
5346 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5348 if(!child_font->font)
5349 if(!load_child_font(font, child_font))
5350 continue;
5352 if(!child_font->font->ft_face)
5353 continue;
5354 g = get_glyph_index(child_font->font, c);
5355 if(g)
5357 *glyph = g;
5358 *linked_font = child_font->font;
5359 return TRUE;
5362 return FALSE;
5365 /*************************************************************
5366 * WineEngGetCharWidth
5369 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5370 LPINT buffer)
5372 UINT c;
5373 GLYPHMETRICS gm;
5374 FT_UInt glyph_index;
5375 GdiFont *linked_font;
5377 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5379 EnterCriticalSection( &freetype_cs );
5380 for(c = firstChar; c <= lastChar; c++) {
5381 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5382 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5383 &gm, 0, NULL, NULL);
5384 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5386 LeaveCriticalSection( &freetype_cs );
5387 return TRUE;
5390 /*************************************************************
5391 * WineEngGetCharABCWidths
5394 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5395 LPABC buffer)
5397 UINT c;
5398 GLYPHMETRICS gm;
5399 FT_UInt glyph_index;
5400 GdiFont *linked_font;
5402 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5404 if(!FT_IS_SCALABLE(font->ft_face))
5405 return FALSE;
5407 EnterCriticalSection( &freetype_cs );
5409 for(c = firstChar; c <= lastChar; c++) {
5410 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5411 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5412 &gm, 0, NULL, NULL);
5413 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5414 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5415 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5416 FONT_GM(linked_font,glyph_index)->bbx;
5418 LeaveCriticalSection( &freetype_cs );
5419 return TRUE;
5422 /*************************************************************
5423 * WineEngGetCharABCWidthsI
5426 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5427 LPABC buffer)
5429 UINT c;
5430 GLYPHMETRICS gm;
5431 FT_UInt glyph_index;
5432 GdiFont *linked_font;
5434 if(!FT_HAS_HORIZONTAL(font->ft_face))
5435 return FALSE;
5437 EnterCriticalSection( &freetype_cs );
5439 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5440 if (!pgi)
5441 for(c = firstChar; c < firstChar+count; c++) {
5442 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5443 &gm, 0, NULL, NULL);
5444 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5445 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5446 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5447 - FONT_GM(linked_font,c)->bbx;
5449 else
5450 for(c = 0; c < count; c++) {
5451 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5452 &gm, 0, NULL, NULL);
5453 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5454 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5455 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5456 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5459 LeaveCriticalSection( &freetype_cs );
5460 return TRUE;
5463 /*************************************************************
5464 * WineEngGetTextExtentExPoint
5467 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5468 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5470 INT idx;
5471 INT nfit = 0, ext;
5472 GLYPHMETRICS gm;
5473 TEXTMETRICW tm;
5474 FT_UInt glyph_index;
5475 GdiFont *linked_font;
5477 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5478 max_ext, size);
5480 EnterCriticalSection( &freetype_cs );
5482 size->cx = 0;
5483 WineEngGetTextMetrics(font, &tm);
5484 size->cy = tm.tmHeight;
5486 for(idx = 0; idx < count; idx++) {
5487 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5488 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5489 &gm, 0, NULL, NULL);
5490 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5491 ext = size->cx;
5492 if (! pnfit || ext <= max_ext) {
5493 ++nfit;
5494 if (dxs)
5495 dxs[idx] = ext;
5499 if (pnfit)
5500 *pnfit = nfit;
5502 LeaveCriticalSection( &freetype_cs );
5503 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5504 return TRUE;
5507 /*************************************************************
5508 * WineEngGetTextExtentExPointI
5511 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5512 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5514 INT idx;
5515 INT nfit = 0, ext;
5516 GLYPHMETRICS gm;
5517 TEXTMETRICW tm;
5519 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5521 EnterCriticalSection( &freetype_cs );
5523 size->cx = 0;
5524 WineEngGetTextMetrics(font, &tm);
5525 size->cy = tm.tmHeight;
5527 for(idx = 0; idx < count; idx++) {
5528 WineEngGetGlyphOutline(font, indices[idx],
5529 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5530 NULL);
5531 size->cx += FONT_GM(font,indices[idx])->adv;
5532 ext = size->cx;
5533 if (! pnfit || ext <= max_ext) {
5534 ++nfit;
5535 if (dxs)
5536 dxs[idx] = ext;
5540 if (pnfit)
5541 *pnfit = nfit;
5543 LeaveCriticalSection( &freetype_cs );
5544 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5545 return TRUE;
5548 /*************************************************************
5549 * WineEngGetFontData
5552 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5553 DWORD cbData)
5555 FT_Face ft_face = font->ft_face;
5556 FT_ULong len;
5557 FT_Error err;
5559 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5560 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5561 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5563 if(!FT_IS_SFNT(ft_face))
5564 return GDI_ERROR;
5566 if(!buf || !cbData)
5567 len = 0;
5568 else
5569 len = cbData;
5571 if(table) { /* MS tags differ in endianness from FT ones */
5572 table = table >> 24 | table << 24 |
5573 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5576 /* make sure value of len is the value freetype says it needs */
5577 if(buf && len)
5579 FT_ULong needed = 0;
5580 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5581 if( !err && needed < len) len = needed;
5583 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5585 if(err) {
5586 TRACE("Can't find table %c%c%c%c\n",
5587 /* bytes were reversed */
5588 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5589 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5590 return GDI_ERROR;
5592 return len;
5595 /*************************************************************
5596 * WineEngGetTextFace
5599 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5601 INT n = strlenW(font->name) + 1;
5602 if(str) {
5603 lstrcpynW(str, font->name, count);
5604 return min(count, n);
5605 } else
5606 return n;
5609 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5611 if (fs) *fs = font->fs;
5612 return font->charset;
5615 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5617 GdiFont *font = dc->gdiFont, *linked_font;
5618 struct list *first_hfont;
5619 BOOL ret;
5621 EnterCriticalSection( &freetype_cs );
5622 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5623 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5624 if(font == linked_font)
5625 *new_hfont = dc->hFont;
5626 else
5628 first_hfont = list_head(&linked_font->hfontlist);
5629 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5631 LeaveCriticalSection( &freetype_cs );
5632 return ret;
5635 /* Retrieve a list of supported Unicode ranges for a given font.
5636 * Can be called with NULL gs to calculate the buffer size. Returns
5637 * the number of ranges found.
5639 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5641 DWORD num_ranges = 0;
5643 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5645 FT_UInt glyph_code;
5646 FT_ULong char_code, char_code_prev;
5648 glyph_code = 0;
5649 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5651 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5652 face->num_glyphs, glyph_code, char_code);
5654 if (!glyph_code) return 0;
5656 if (gs)
5658 gs->ranges[0].wcLow = (USHORT)char_code;
5659 gs->ranges[0].cGlyphs = 0;
5660 gs->cGlyphsSupported = 0;
5663 num_ranges = 1;
5664 while (glyph_code)
5666 if (char_code < char_code_prev)
5668 ERR("expected increasing char code from FT_Get_Next_Char\n");
5669 return 0;
5671 if (char_code - char_code_prev > 1)
5673 num_ranges++;
5674 if (gs)
5676 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5677 gs->ranges[num_ranges - 1].cGlyphs = 1;
5678 gs->cGlyphsSupported++;
5681 else if (gs)
5683 gs->ranges[num_ranges - 1].cGlyphs++;
5684 gs->cGlyphsSupported++;
5686 char_code_prev = char_code;
5687 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5690 else
5691 FIXME("encoding %u not supported\n", face->charmap->encoding);
5693 return num_ranges;
5696 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5698 DWORD size = 0;
5699 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5701 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5702 if (glyphset)
5704 glyphset->cbThis = size;
5705 glyphset->cRanges = num_ranges;
5707 return size;
5710 /*************************************************************
5711 * FontIsLinked
5713 BOOL WineEngFontIsLinked(GdiFont *font)
5715 BOOL ret;
5716 EnterCriticalSection( &freetype_cs );
5717 ret = !list_empty(&font->child_fonts);
5718 LeaveCriticalSection( &freetype_cs );
5719 return ret;
5722 static BOOL is_hinting_enabled(void)
5724 /* Use the >= 2.2.0 function if available */
5725 if(pFT_Get_TrueType_Engine_Type)
5727 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5728 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5730 #ifdef FT_DRIVER_HAS_HINTER
5731 else
5733 FT_Module mod;
5735 /* otherwise if we've been compiled with < 2.2.0 headers
5736 use the internal macro */
5737 mod = pFT_Get_Module(library, "truetype");
5738 if(mod && FT_DRIVER_HAS_HINTER(mod))
5739 return TRUE;
5741 #endif
5743 return FALSE;
5746 /*************************************************************************
5747 * GetRasterizerCaps (GDI32.@)
5749 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5751 static int hinting = -1;
5753 if(hinting == -1)
5755 hinting = is_hinting_enabled();
5756 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5759 lprs->nSize = sizeof(RASTERIZER_STATUS);
5760 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5761 lprs->nLanguageID = 0;
5762 return TRUE;
5765 /*************************************************************
5766 * WineEngRealizationInfo
5768 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5770 FIXME("(%p, %p): stub!\n", font, info);
5772 info->flags = 1;
5773 if(FT_IS_SCALABLE(font->ft_face))
5774 info->flags |= 2;
5776 info->cache_num = font->cache_num;
5777 info->unknown2 = -1;
5778 return TRUE;
5781 /*************************************************************************
5782 * Kerning support for TrueType fonts
5784 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5786 struct TT_kern_table
5788 USHORT version;
5789 USHORT nTables;
5792 struct TT_kern_subtable
5794 USHORT version;
5795 USHORT length;
5796 union
5798 USHORT word;
5799 struct
5801 USHORT horizontal : 1;
5802 USHORT minimum : 1;
5803 USHORT cross_stream: 1;
5804 USHORT override : 1;
5805 USHORT reserved1 : 4;
5806 USHORT format : 8;
5807 } bits;
5808 } coverage;
5811 struct TT_format0_kern_subtable
5813 USHORT nPairs;
5814 USHORT searchRange;
5815 USHORT entrySelector;
5816 USHORT rangeShift;
5819 struct TT_kern_pair
5821 USHORT left;
5822 USHORT right;
5823 short value;
5826 static DWORD parse_format0_kern_subtable(GdiFont *font,
5827 const struct TT_format0_kern_subtable *tt_f0_ks,
5828 const USHORT *glyph_to_char,
5829 KERNINGPAIR *kern_pair, DWORD cPairs)
5831 USHORT i, nPairs;
5832 const struct TT_kern_pair *tt_kern_pair;
5834 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5836 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5838 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5839 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5840 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5842 if (!kern_pair || !cPairs)
5843 return nPairs;
5845 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5847 nPairs = min(nPairs, cPairs);
5849 for (i = 0; i < nPairs; i++)
5851 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5852 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5853 /* this algorithm appears to better match what Windows does */
5854 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5855 if (kern_pair->iKernAmount < 0)
5857 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5858 kern_pair->iKernAmount -= font->ppem;
5860 else if (kern_pair->iKernAmount > 0)
5862 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5863 kern_pair->iKernAmount += font->ppem;
5865 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5867 TRACE("left %u right %u value %d\n",
5868 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5870 kern_pair++;
5872 TRACE("copied %u entries\n", nPairs);
5873 return nPairs;
5876 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5878 DWORD length;
5879 void *buf;
5880 const struct TT_kern_table *tt_kern_table;
5881 const struct TT_kern_subtable *tt_kern_subtable;
5882 USHORT i, nTables;
5883 USHORT *glyph_to_char;
5885 EnterCriticalSection( &freetype_cs );
5886 if (font->total_kern_pairs != (DWORD)-1)
5888 if (cPairs && kern_pair)
5890 cPairs = min(cPairs, font->total_kern_pairs);
5891 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5892 LeaveCriticalSection( &freetype_cs );
5893 return cPairs;
5895 LeaveCriticalSection( &freetype_cs );
5896 return font->total_kern_pairs;
5899 font->total_kern_pairs = 0;
5901 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5903 if (length == GDI_ERROR)
5905 TRACE("no kerning data in the font\n");
5906 LeaveCriticalSection( &freetype_cs );
5907 return 0;
5910 buf = HeapAlloc(GetProcessHeap(), 0, length);
5911 if (!buf)
5913 WARN("Out of memory\n");
5914 LeaveCriticalSection( &freetype_cs );
5915 return 0;
5918 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5920 /* build a glyph index to char code map */
5921 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5922 if (!glyph_to_char)
5924 WARN("Out of memory allocating a glyph index to char code map\n");
5925 HeapFree(GetProcessHeap(), 0, buf);
5926 LeaveCriticalSection( &freetype_cs );
5927 return 0;
5930 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5932 FT_UInt glyph_code;
5933 FT_ULong char_code;
5935 glyph_code = 0;
5936 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5938 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5939 font->ft_face->num_glyphs, glyph_code, char_code);
5941 while (glyph_code)
5943 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5945 /* FIXME: This doesn't match what Windows does: it does some fancy
5946 * things with duplicate glyph index to char code mappings, while
5947 * we just avoid overriding existing entries.
5949 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5950 glyph_to_char[glyph_code] = (USHORT)char_code;
5952 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5955 else
5957 ULONG n;
5959 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5960 for (n = 0; n <= 65535; n++)
5961 glyph_to_char[n] = (USHORT)n;
5964 tt_kern_table = buf;
5965 nTables = GET_BE_WORD(tt_kern_table->nTables);
5966 TRACE("version %u, nTables %u\n",
5967 GET_BE_WORD(tt_kern_table->version), nTables);
5969 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5971 for (i = 0; i < nTables; i++)
5973 struct TT_kern_subtable tt_kern_subtable_copy;
5975 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5976 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5977 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5979 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5980 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5981 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5983 /* According to the TrueType specification this is the only format
5984 * that will be properly interpreted by Windows and OS/2
5986 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5988 DWORD new_chunk, old_total = font->total_kern_pairs;
5990 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5991 glyph_to_char, NULL, 0);
5992 font->total_kern_pairs += new_chunk;
5994 if (!font->kern_pairs)
5995 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5996 font->total_kern_pairs * sizeof(*font->kern_pairs));
5997 else
5998 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5999 font->total_kern_pairs * sizeof(*font->kern_pairs));
6001 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6002 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6004 else
6005 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6007 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6010 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6011 HeapFree(GetProcessHeap(), 0, buf);
6013 if (cPairs && kern_pair)
6015 cPairs = min(cPairs, font->total_kern_pairs);
6016 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6017 LeaveCriticalSection( &freetype_cs );
6018 return cPairs;
6020 LeaveCriticalSection( &freetype_cs );
6021 return font->total_kern_pairs;
6024 #else /* HAVE_FREETYPE */
6026 /*************************************************************************/
6028 BOOL WineEngInit(void)
6030 return FALSE;
6032 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6034 return NULL;
6036 BOOL WineEngDestroyFontInstance(HFONT hfont)
6038 return FALSE;
6041 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6043 return 1;
6046 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6047 LPWORD pgi, DWORD flags)
6049 return GDI_ERROR;
6052 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6053 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6054 const MAT2* lpmat)
6056 ERR("called but we don't have FreeType\n");
6057 return GDI_ERROR;
6060 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6062 ERR("called but we don't have FreeType\n");
6063 return FALSE;
6066 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6067 OUTLINETEXTMETRICW *potm)
6069 ERR("called but we don't have FreeType\n");
6070 return 0;
6073 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6074 LPINT buffer)
6076 ERR("called but we don't have FreeType\n");
6077 return FALSE;
6080 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6081 LPABC buffer)
6083 ERR("called but we don't have FreeType\n");
6084 return FALSE;
6087 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6088 LPABC buffer)
6090 ERR("called but we don't have FreeType\n");
6091 return FALSE;
6094 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6095 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6097 ERR("called but we don't have FreeType\n");
6098 return FALSE;
6101 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6102 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6104 ERR("called but we don't have FreeType\n");
6105 return FALSE;
6108 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6109 DWORD cbData)
6111 ERR("called but we don't have FreeType\n");
6112 return GDI_ERROR;
6115 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6117 ERR("called but we don't have FreeType\n");
6118 return 0;
6121 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6123 FIXME(":stub\n");
6124 return 1;
6127 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6129 FIXME(":stub\n");
6130 return TRUE;
6133 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6135 FIXME(":stub\n");
6136 return NULL;
6139 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6141 FIXME(":stub\n");
6142 return DEFAULT_CHARSET;
6145 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6147 return FALSE;
6150 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6152 FIXME("(%p, %p): stub\n", font, glyphset);
6153 return 0;
6156 BOOL WineEngFontIsLinked(GdiFont *font)
6158 return FALSE;
6161 /*************************************************************************
6162 * GetRasterizerCaps (GDI32.@)
6164 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6166 lprs->nSize = sizeof(RASTERIZER_STATUS);
6167 lprs->wFlags = 0;
6168 lprs->nLanguageID = 0;
6169 return TRUE;
6172 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6174 ERR("called but we don't have FreeType\n");
6175 return 0;
6178 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6180 ERR("called but we don't have FreeType\n");
6181 return FALSE;
6184 #endif /* HAVE_FREETYPE */