push 337eb2e2d902d84a5d689451984c5832d7e04fc4
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob2894dca2e8fbae5d6a2b42e87e8e5054da5b6751
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 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/unicode.h"
88 #include "wine/debug.h"
89 #include "wine/list.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FREETYPE
95 #ifdef HAVE_FT2BUILD_H
96 #include <ft2build.h>
97 #endif
98 #ifdef HAVE_FREETYPE_FREETYPE_H
99 #include <freetype/freetype.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FTGLYPH_H
102 #include <freetype/ftglyph.h>
103 #endif
104 #ifdef HAVE_FREETYPE_TTTABLES_H
105 #include <freetype/tttables.h>
106 #endif
107 #ifdef HAVE_FREETYPE_FTTYPES_H
108 #include <freetype/fttypes.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTSNAMES_H
111 #include <freetype/ftsnames.h>
112 #else
113 # ifdef HAVE_FREETYPE_FTNAMES_H
114 # include <freetype/ftnames.h>
115 # endif
116 #endif
117 #ifdef HAVE_FREETYPE_TTNAMEID_H
118 #include <freetype/ttnameid.h>
119 #endif
120 #ifdef HAVE_FREETYPE_FTOUTLN_H
121 #include <freetype/ftoutln.h>
122 #endif
123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
124 #include <freetype/internal/sfnt.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTTRIGON_H
127 #include <freetype/fttrigon.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTWINFNT_H
130 #include <freetype/ftwinfnt.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTMODAPI_H
133 #include <freetype/ftmodapi.h>
134 #endif
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 typedef enum
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
143 #endif
145 static FT_Library library = 0;
146 typedef struct
148 FT_Int major;
149 FT_Int minor;
150 FT_Int patch;
151 } FT_Version_t;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
170 #else
171 MAKE_FUNCPTR(FT_MulFix);
172 #endif
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
183 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
184 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
185 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
186 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
187 #ifdef HAVE_FREETYPE_FTWINFNT_H
188 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
189 #endif
191 #ifdef SONAME_LIBFONTCONFIG
192 #include <fontconfig/fontconfig.h>
193 MAKE_FUNCPTR(FcConfigGetCurrent);
194 MAKE_FUNCPTR(FcFontList);
195 MAKE_FUNCPTR(FcFontSetDestroy);
196 MAKE_FUNCPTR(FcInit);
197 MAKE_FUNCPTR(FcObjectSetAdd);
198 MAKE_FUNCPTR(FcObjectSetCreate);
199 MAKE_FUNCPTR(FcObjectSetDestroy);
200 MAKE_FUNCPTR(FcPatternCreate);
201 MAKE_FUNCPTR(FcPatternDestroy);
202 MAKE_FUNCPTR(FcPatternGetBool);
203 MAKE_FUNCPTR(FcPatternGetString);
204 #endif
206 #undef MAKE_FUNCPTR
208 #ifndef FT_MAKE_TAG
209 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
210 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
211 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
212 #endif
214 #ifndef ft_encoding_none
215 #define FT_ENCODING_NONE ft_encoding_none
216 #endif
217 #ifndef ft_encoding_ms_symbol
218 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
219 #endif
220 #ifndef ft_encoding_unicode
221 #define FT_ENCODING_UNICODE ft_encoding_unicode
222 #endif
223 #ifndef ft_encoding_apple_roman
224 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
225 #endif
227 #ifdef WORDS_BIGENDIAN
228 #define GET_BE_WORD(x) (x)
229 #else
230 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
231 #endif
233 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
234 typedef struct {
235 FT_Short height;
236 FT_Short width;
237 FT_Pos size;
238 FT_Pos x_ppem;
239 FT_Pos y_ppem;
240 FT_Short internal_leading;
241 } Bitmap_Size;
243 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
244 So to let this compile on older versions of FreeType we'll define the
245 new structure here. */
246 typedef struct {
247 FT_Short height, width;
248 FT_Pos size, x_ppem, y_ppem;
249 } My_FT_Bitmap_Size;
251 struct enum_data
253 ENUMLOGFONTEXW elf;
254 NEWTEXTMETRICEXW ntm;
255 DWORD type;
258 typedef struct tagFace {
259 struct list entry;
260 WCHAR *StyleName;
261 char *file;
262 void *font_data_ptr;
263 DWORD font_data_size;
264 FT_Long face_index;
265 FONTSIGNATURE fs;
266 FONTSIGNATURE fs_links;
267 DWORD ntmFlags;
268 FT_Fixed font_version;
269 BOOL scalable;
270 Bitmap_Size size; /* set if face is a bitmap */
271 BOOL external; /* TRUE if we should manually add this font to the registry */
272 struct tagFamily *family;
273 /* Cached data for Enum */
274 struct enum_data *cached_enum_data;
275 } Face;
277 typedef struct tagFamily {
278 struct list entry;
279 const WCHAR *FamilyName;
280 struct list faces;
281 } Family;
283 typedef struct {
284 GLYPHMETRICS gm;
285 INT adv; /* These three hold to widths of the unrotated chars */
286 INT lsb;
287 INT bbx;
288 BOOL init;
289 } GM;
291 typedef struct {
292 FLOAT eM11, eM12;
293 FLOAT eM21, eM22;
294 } FMAT2;
296 typedef struct {
297 DWORD hash;
298 LOGFONTW lf;
299 FMAT2 matrix;
300 BOOL can_use_bitmap;
301 } FONT_DESC;
303 typedef struct tagHFONTLIST {
304 struct list entry;
305 HFONT hfont;
306 } HFONTLIST;
308 typedef struct {
309 struct list entry;
310 Face *face;
311 GdiFont *font;
312 } CHILD_FONT;
314 struct tagGdiFont {
315 struct list entry;
316 GM **gm;
317 DWORD gmsize;
318 struct list hfontlist;
319 OUTLINETEXTMETRICW *potm;
320 DWORD total_kern_pairs;
321 KERNINGPAIR *kern_pairs;
322 struct list child_fonts;
324 /* the following members can be accessed without locking, they are never modified after creation */
325 FT_Face ft_face;
326 struct font_mapping *mapping;
327 LPWSTR name;
328 int charset;
329 int codepage;
330 BOOL fake_italic;
331 BOOL fake_bold;
332 BYTE underline;
333 BYTE strikeout;
334 INT orientation;
335 FONT_DESC font_desc;
336 LONG aveWidth, ppem;
337 double scale_y;
338 SHORT yMax;
339 SHORT yMin;
340 DWORD ntmFlags;
341 FONTSIGNATURE fs;
342 GdiFont *base_font;
343 VOID *GSUB_Table;
344 DWORD cache_num;
347 typedef struct {
348 struct list entry;
349 const WCHAR *font_name;
350 struct list links;
351 } SYSTEM_LINKS;
353 #define GM_BLOCK_SIZE 128
354 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
356 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
357 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
358 #define UNUSED_CACHE_SIZE 10
359 static struct list child_font_list = LIST_INIT(child_font_list);
360 static struct list system_links = LIST_INIT(system_links);
362 static struct list font_subst_list = LIST_INIT(font_subst_list);
364 static struct list font_list = LIST_INIT(font_list);
366 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
367 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
368 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
370 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
371 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372 'W','i','n','d','o','w','s','\\',
373 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374 'F','o','n','t','s','\0'};
376 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
377 'W','i','n','d','o','w','s',' ','N','T','\\',
378 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
379 'F','o','n','t','s','\0'};
381 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
382 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
383 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
384 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
386 static const WCHAR * const SystemFontValues[4] = {
387 System_Value,
388 OEMFont_Value,
389 FixedSys_Value,
390 NULL
393 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
394 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
396 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
397 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
398 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
399 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
400 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
401 'E','u','r','o','p','e','a','n','\0'};
402 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
403 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
404 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
405 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
406 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
407 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
408 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
409 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
410 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
411 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
412 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
413 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
415 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
416 WesternW, /*00*/
417 Central_EuropeanW,
418 CyrillicW,
419 GreekW,
420 TurkishW,
421 HebrewW,
422 ArabicW,
423 BalticW,
424 VietnameseW, /*08*/
425 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
426 ThaiW,
427 JapaneseW,
428 CHINESE_GB2312W,
429 HangulW,
430 CHINESE_BIG5W,
431 Hangul_Johab_W,
432 NULL, NULL, /*23*/
433 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
434 SymbolW /*31*/
437 typedef struct {
438 WCHAR *name;
439 INT charset;
440 } NameCs;
442 typedef struct tagFontSubst {
443 struct list entry;
444 NameCs from;
445 NameCs to;
446 } FontSubst;
448 struct font_mapping
450 struct list entry;
451 int refcount;
452 dev_t dev;
453 ino_t ino;
454 void *data;
455 size_t size;
458 static struct list mappings_list = LIST_INIT( mappings_list );
460 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
462 static CRITICAL_SECTION freetype_cs;
463 static CRITICAL_SECTION_DEBUG critsect_debug =
465 0, 0, &freetype_cs,
466 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
467 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
469 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
471 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
473 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
474 static BOOL use_default_fallback = FALSE;
476 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
478 /****************************************
479 * Notes on .fon files
481 * The fonts System, FixedSys and Terminal are special. There are typically multiple
482 * versions installed for different resolutions and codepages. Windows stores which one to use
483 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
484 * Key Meaning
485 * FIXEDFON.FON FixedSys
486 * FONTS.FON System
487 * OEMFONT.FON Terminal
488 * LogPixels Current dpi set by the display control panel applet
489 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
490 * also has a LogPixels value that appears to mirror this)
492 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
493 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
494 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
495 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
496 * so that makes sense.
498 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
499 * to be mapped into the registry on Windows 2000 at least).
500 * I have
501 * woafont=app850.fon
502 * ega80woa.fon=ega80850.fon
503 * ega40woa.fon=ega40850.fon
504 * cga80woa.fon=cga80850.fon
505 * cga40woa.fon=cga40850.fon
508 /* These are all structures needed for the GSUB table */
510 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
511 #define TATEGAKI_LOWER_BOUND 0x02F1
513 typedef struct {
514 DWORD version;
515 WORD ScriptList;
516 WORD FeatureList;
517 WORD LookupList;
518 } GSUB_Header;
520 typedef struct {
521 CHAR ScriptTag[4];
522 WORD Script;
523 } GSUB_ScriptRecord;
525 typedef struct {
526 WORD ScriptCount;
527 GSUB_ScriptRecord ScriptRecord[1];
528 } GSUB_ScriptList;
530 typedef struct {
531 CHAR LangSysTag[4];
532 WORD LangSys;
533 } GSUB_LangSysRecord;
535 typedef struct {
536 WORD DefaultLangSys;
537 WORD LangSysCount;
538 GSUB_LangSysRecord LangSysRecord[1];
539 } GSUB_Script;
541 typedef struct {
542 WORD LookupOrder; /* Reserved */
543 WORD ReqFeatureIndex;
544 WORD FeatureCount;
545 WORD FeatureIndex[1];
546 } GSUB_LangSys;
548 typedef struct {
549 CHAR FeatureTag[4];
550 WORD Feature;
551 } GSUB_FeatureRecord;
553 typedef struct {
554 WORD FeatureCount;
555 GSUB_FeatureRecord FeatureRecord[1];
556 } GSUB_FeatureList;
558 typedef struct {
559 WORD FeatureParams; /* Reserved */
560 WORD LookupCount;
561 WORD LookupListIndex[1];
562 } GSUB_Feature;
564 typedef struct {
565 WORD LookupCount;
566 WORD Lookup[1];
567 } GSUB_LookupList;
569 typedef struct {
570 WORD LookupType;
571 WORD LookupFlag;
572 WORD SubTableCount;
573 WORD SubTable[1];
574 } GSUB_LookupTable;
576 typedef struct {
577 WORD CoverageFormat;
578 WORD GlyphCount;
579 WORD GlyphArray[1];
580 } GSUB_CoverageFormat1;
582 typedef struct {
583 WORD Start;
584 WORD End;
585 WORD StartCoverageIndex;
586 } GSUB_RangeRecord;
588 typedef struct {
589 WORD CoverageFormat;
590 WORD RangeCount;
591 GSUB_RangeRecord RangeRecord[1];
592 } GSUB_CoverageFormat2;
594 typedef struct {
595 WORD SubstFormat; /* = 1 */
596 WORD Coverage;
597 WORD DeltaGlyphID;
598 } GSUB_SingleSubstFormat1;
600 typedef struct {
601 WORD SubstFormat; /* = 2 */
602 WORD Coverage;
603 WORD GlyphCount;
604 WORD Substitute[1];
605 }GSUB_SingleSubstFormat2;
607 #ifdef HAVE_CARBON_CARBON_H
608 static char *find_cache_dir(void)
610 FSRef ref;
611 OSErr err;
612 static char cached_path[MAX_PATH];
613 static const char *wine = "/Wine", *fonts = "/Fonts";
615 if(*cached_path) return cached_path;
617 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
618 if(err != noErr)
620 WARN("can't create cached data folder\n");
621 return NULL;
623 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
624 if(err != noErr)
626 WARN("can't create cached data path\n");
627 *cached_path = '\0';
628 return NULL;
630 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
632 ERR("Could not create full path\n");
633 *cached_path = '\0';
634 return NULL;
636 strcat(cached_path, wine);
638 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
640 WARN("Couldn't mkdir %s\n", cached_path);
641 *cached_path = '\0';
642 return NULL;
644 strcat(cached_path, fonts);
645 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
647 WARN("Couldn't mkdir %s\n", cached_path);
648 *cached_path = '\0';
649 return NULL;
651 return cached_path;
654 /******************************************************************
655 * expand_mac_font
657 * Extracts individual TrueType font files from a Mac suitcase font
658 * and saves them into the user's caches directory (see
659 * find_cache_dir()).
660 * Returns a NULL terminated array of filenames.
662 * We do this because they are apps that try to read ttf files
663 * themselves and they don't like Mac suitcase files.
665 static char **expand_mac_font(const char *path)
667 FSRef ref;
668 SInt16 res_ref;
669 OSStatus s;
670 unsigned int idx;
671 const char *out_dir;
672 const char *filename;
673 int output_len;
674 struct {
675 char **array;
676 unsigned int size, max_size;
677 } ret;
679 TRACE("path %s\n", path);
681 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
682 if(s != noErr)
684 WARN("failed to get ref\n");
685 return NULL;
688 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
689 if(s != noErr)
691 TRACE("no data fork, so trying resource fork\n");
692 res_ref = FSOpenResFile(&ref, fsRdPerm);
693 if(res_ref == -1)
695 TRACE("unable to open resource fork\n");
696 return NULL;
700 ret.size = 0;
701 ret.max_size = 10;
702 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
703 if(!ret.array)
705 CloseResFile(res_ref);
706 return NULL;
709 out_dir = find_cache_dir();
711 filename = strrchr(path, '/');
712 if(!filename) filename = path;
713 else filename++;
715 /* output filename has the form out_dir/filename_%04x.ttf */
716 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
718 UseResFile(res_ref);
719 idx = 1;
720 while(1)
722 FamRec *fam_rec;
723 unsigned short *num_faces_ptr, num_faces, face;
724 AsscEntry *assoc;
725 Handle fond;
726 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
728 fond = Get1IndResource(fond_res, idx);
729 if(!fond) break;
730 TRACE("got fond resource %d\n", idx);
731 HLock(fond);
733 fam_rec = *(FamRec**)fond;
734 num_faces_ptr = (unsigned short *)(fam_rec + 1);
735 num_faces = GET_BE_WORD(*num_faces_ptr);
736 num_faces++;
737 assoc = (AsscEntry*)(num_faces_ptr + 1);
738 TRACE("num faces %04x\n", num_faces);
739 for(face = 0; face < num_faces; face++, assoc++)
741 Handle sfnt;
742 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
743 unsigned short size, font_id;
744 char *output;
746 size = GET_BE_WORD(assoc->fontSize);
747 font_id = GET_BE_WORD(assoc->fontID);
748 if(size != 0)
750 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
751 continue;
754 TRACE("trying to load sfnt id %04x\n", font_id);
755 sfnt = GetResource(sfnt_res, font_id);
756 if(!sfnt)
758 TRACE("can't get sfnt resource %04x\n", font_id);
759 continue;
762 output = HeapAlloc(GetProcessHeap(), 0, output_len);
763 if(output)
765 int fd;
767 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
769 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
770 if(fd != -1 || errno == EEXIST)
772 if(fd != -1)
774 unsigned char *sfnt_data;
776 HLock(sfnt);
777 sfnt_data = *(unsigned char**)sfnt;
778 write(fd, sfnt_data, GetHandleSize(sfnt));
779 HUnlock(sfnt);
780 close(fd);
782 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
784 ret.max_size *= 2;
785 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
787 ret.array[ret.size++] = output;
789 else
791 WARN("unable to create %s\n", output);
792 HeapFree(GetProcessHeap(), 0, output);
795 ReleaseResource(sfnt);
797 HUnlock(fond);
798 ReleaseResource(fond);
799 idx++;
801 CloseResFile(res_ref);
803 return ret.array;
806 #endif /* HAVE_CARBON_CARBON_H */
808 static inline BOOL is_win9x(void)
810 return GetVersion() & 0x80000000;
813 This function builds an FT_Fixed from a double. It fails if the absolute
814 value of the float number is greater than 32768.
816 static inline FT_Fixed FT_FixedFromFloat(double f)
818 return f * 0x10000;
822 This function builds an FT_Fixed from a FIXED. It simply put f.value
823 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
825 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
827 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
831 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
833 Family *family;
834 Face *face;
835 const char *file;
836 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
837 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
839 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
840 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
842 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
844 if(face_name && strcmpiW(face_name, family->FamilyName))
845 continue;
846 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
848 if (!face->file)
849 continue;
850 file = strrchr(face->file, '/');
851 if(!file)
852 file = face->file;
853 else
854 file++;
855 if(!strcasecmp(file, file_nameA))
857 HeapFree(GetProcessHeap(), 0, file_nameA);
858 return face;
862 HeapFree(GetProcessHeap(), 0, file_nameA);
863 return NULL;
866 static Family *find_family_from_name(const WCHAR *name)
868 Family *family;
870 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
872 if(!strcmpiW(family->FamilyName, name))
873 return family;
876 return NULL;
879 static void DumpSubstList(void)
881 FontSubst *psub;
883 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
885 if(psub->from.charset != -1 || psub->to.charset != -1)
886 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
887 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
888 else
889 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
890 debugstr_w(psub->to.name));
892 return;
895 static LPWSTR strdupW(LPCWSTR p)
897 LPWSTR ret;
898 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
899 ret = HeapAlloc(GetProcessHeap(), 0, len);
900 memcpy(ret, p, len);
901 return ret;
904 static LPSTR strdupA(LPCSTR p)
906 LPSTR ret;
907 DWORD len = (strlen(p) + 1);
908 ret = HeapAlloc(GetProcessHeap(), 0, len);
909 memcpy(ret, p, len);
910 return ret;
913 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
914 INT from_charset)
916 FontSubst *element;
918 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
920 if(!strcmpiW(element->from.name, from_name) &&
921 (element->from.charset == from_charset ||
922 element->from.charset == -1))
923 return element;
926 return NULL;
929 #define ADD_FONT_SUBST_FORCE 1
931 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
933 FontSubst *from_exist, *to_exist;
935 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
937 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
939 list_remove(&from_exist->entry);
940 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
941 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
942 HeapFree(GetProcessHeap(), 0, from_exist);
943 from_exist = NULL;
946 if(!from_exist)
948 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
950 if(to_exist)
952 HeapFree(GetProcessHeap(), 0, subst->to.name);
953 subst->to.name = strdupW(to_exist->to.name);
956 list_add_tail(subst_list, &subst->entry);
958 return TRUE;
961 HeapFree(GetProcessHeap(), 0, subst->from.name);
962 HeapFree(GetProcessHeap(), 0, subst->to.name);
963 HeapFree(GetProcessHeap(), 0, subst);
964 return FALSE;
967 static void split_subst_info(NameCs *nc, LPSTR str)
969 CHAR *p = strrchr(str, ',');
970 DWORD len;
972 nc->charset = -1;
973 if(p && *(p+1)) {
974 nc->charset = strtol(p+1, NULL, 10);
975 *p = '\0';
977 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
978 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
979 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
982 static void LoadSubstList(void)
984 FontSubst *psub;
985 HKEY hkey;
986 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
987 LPSTR value;
988 LPVOID data;
990 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
991 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
992 &hkey) == ERROR_SUCCESS) {
994 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
995 &valuelen, &datalen, NULL, NULL);
997 valuelen++; /* returned value doesn't include room for '\0' */
998 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
999 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1001 dlen = datalen;
1002 vlen = valuelen;
1003 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1004 &dlen) == ERROR_SUCCESS) {
1005 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1007 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1008 split_subst_info(&psub->from, value);
1009 split_subst_info(&psub->to, data);
1011 /* Win 2000 doesn't allow mapping between different charsets
1012 or mapping of DEFAULT_CHARSET */
1013 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1014 psub->to.charset == DEFAULT_CHARSET) {
1015 HeapFree(GetProcessHeap(), 0, psub->to.name);
1016 HeapFree(GetProcessHeap(), 0, psub->from.name);
1017 HeapFree(GetProcessHeap(), 0, psub);
1018 } else {
1019 add_font_subst(&font_subst_list, psub, 0);
1021 /* reset dlen and vlen */
1022 dlen = datalen;
1023 vlen = valuelen;
1025 HeapFree(GetProcessHeap(), 0, data);
1026 HeapFree(GetProcessHeap(), 0, value);
1027 RegCloseKey(hkey);
1032 /*****************************************************************
1033 * get_name_table_entry
1035 * Supply the platform, encoding, language and name ids in req
1036 * and if the name exists the function will fill in the string
1037 * and string_len members. The string is owned by FreeType so
1038 * don't free it. Returns TRUE if the name is found else FALSE.
1040 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1042 FT_SfntName name;
1043 FT_UInt num_names, name_index;
1045 if(FT_IS_SFNT(ft_face))
1047 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1049 for(name_index = 0; name_index < num_names; name_index++)
1051 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1053 if((name.platform_id == req->platform_id) &&
1054 (name.encoding_id == req->encoding_id) &&
1055 (name.language_id == req->language_id) &&
1056 (name.name_id == req->name_id))
1058 req->string = name.string;
1059 req->string_len = name.string_len;
1060 return TRUE;
1065 req->string = NULL;
1066 req->string_len = 0;
1067 return FALSE;
1070 static WCHAR *get_familyname(FT_Face ft_face)
1072 WCHAR *family = NULL;
1073 FT_SfntName name;
1075 name.platform_id = TT_PLATFORM_MICROSOFT;
1076 name.encoding_id = TT_MS_ID_UNICODE_CS;
1077 name.language_id = GetUserDefaultLCID();
1078 name.name_id = TT_NAME_ID_FONT_FAMILY;
1080 if(get_name_table_entry(ft_face, &name))
1082 FT_UInt i;
1084 /* String is not nul terminated and string_len is a byte length. */
1085 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1086 for(i = 0; i < name.string_len / 2; i++)
1088 WORD *tmp = (WORD *)&name.string[i * 2];
1089 family[i] = GET_BE_WORD(*tmp);
1091 family[i] = 0;
1092 TRACE("Got localised name %s\n", debugstr_w(family));
1095 return family;
1099 /*****************************************************************
1100 * load_sfnt_table
1102 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1103 * of FreeType that don't export this function.
1106 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1109 FT_Error err;
1111 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1112 if(pFT_Load_Sfnt_Table)
1114 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1116 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1117 else /* Do it the hard way */
1119 TT_Face tt_face = (TT_Face) ft_face;
1120 SFNT_Interface *sfnt;
1121 if (FT_Version.major==2 && FT_Version.minor==0)
1123 /* 2.0.x */
1124 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1126 else
1128 /* A field was added in the middle of the structure in 2.1.x */
1129 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1131 err = sfnt->load_any(tt_face, table, offset, buf, len);
1133 #else
1134 else
1136 static int msg;
1137 if(!msg)
1139 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1140 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1141 "Please upgrade your freetype library.\n");
1142 msg++;
1144 err = FT_Err_Unimplemented_Feature;
1146 #endif
1147 return err;
1150 static inline int TestStyles(DWORD flags, DWORD styles)
1152 return (flags & styles) == styles;
1155 static int StyleOrdering(Face *face)
1157 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1158 return 3;
1159 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1160 return 2;
1161 if (TestStyles(face->ntmFlags, NTM_BOLD))
1162 return 1;
1163 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1164 return 0;
1166 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1167 debugstr_w(face->family->FamilyName),
1168 debugstr_w(face->StyleName),
1169 face->ntmFlags);
1171 return 9999;
1174 /* Add a style of face to a font family using an ordering of the list such
1175 that regular fonts come before bold and italic, and single styles come
1176 before compound styles. */
1177 static void AddFaceToFamily(Face *face, Family *family)
1179 struct list *entry;
1181 LIST_FOR_EACH( entry, &family->faces )
1183 Face *ent = LIST_ENTRY(entry, Face, entry);
1184 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1186 list_add_before( entry, &face->entry );
1189 #define ADDFONT_EXTERNAL_FONT 0x01
1190 #define ADDFONT_FORCE_BITMAP 0x02
1191 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1193 FT_Face ft_face;
1194 TT_OS2 *pOS2;
1195 TT_Header *pHeader = NULL;
1196 WCHAR *english_family, *localised_family, *StyleW;
1197 DWORD len;
1198 Family *family;
1199 Face *face;
1200 struct list *family_elem_ptr, *face_elem_ptr;
1201 FT_Error err;
1202 FT_Long face_index = 0, num_faces;
1203 #ifdef HAVE_FREETYPE_FTWINFNT_H
1204 FT_WinFNT_HeaderRec winfnt_header;
1205 #endif
1206 int i, bitmap_num, internal_leading;
1207 FONTSIGNATURE fs;
1209 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1210 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1212 #ifdef HAVE_CARBON_CARBON_H
1213 if(file && !fake_family)
1215 char **mac_list = expand_mac_font(file);
1216 if(mac_list)
1218 BOOL had_one = FALSE;
1219 char **cursor;
1220 for(cursor = mac_list; *cursor; cursor++)
1222 had_one = TRUE;
1223 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1224 HeapFree(GetProcessHeap(), 0, *cursor);
1226 HeapFree(GetProcessHeap(), 0, mac_list);
1227 if(had_one)
1228 return 1;
1231 #endif /* HAVE_CARBON_CARBON_H */
1233 do {
1234 char *family_name = fake_family;
1236 if (file)
1238 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1239 err = pFT_New_Face(library, file, face_index, &ft_face);
1240 } else
1242 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1243 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1246 if(err != 0) {
1247 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1248 return 0;
1251 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*/
1252 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1253 pFT_Done_Face(ft_face);
1254 return 0;
1257 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1258 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1259 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1260 pFT_Done_Face(ft_face);
1261 return 0;
1264 if(FT_IS_SFNT(ft_face))
1266 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1267 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1268 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1270 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1271 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1272 pFT_Done_Face(ft_face);
1273 return 0;
1276 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1277 we don't want to load these. */
1278 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1280 FT_ULong len = 0;
1282 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1284 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1285 pFT_Done_Face(ft_face);
1286 return 0;
1291 if(!ft_face->family_name || !ft_face->style_name) {
1292 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1293 pFT_Done_Face(ft_face);
1294 return 0;
1297 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1299 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1300 pFT_Done_Face(ft_face);
1301 return 0;
1304 if (target_family)
1306 localised_family = get_familyname(ft_face);
1307 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1309 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1310 HeapFree(GetProcessHeap(), 0, localised_family);
1311 num_faces = ft_face->num_faces;
1312 pFT_Done_Face(ft_face);
1313 continue;
1315 HeapFree(GetProcessHeap(), 0, localised_family);
1318 if(!family_name)
1319 family_name = ft_face->family_name;
1321 bitmap_num = 0;
1322 do {
1323 My_FT_Bitmap_Size *size = NULL;
1324 FT_ULong tmp_size;
1326 if(!FT_IS_SCALABLE(ft_face))
1327 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1329 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1330 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1331 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1333 localised_family = NULL;
1334 if(!fake_family) {
1335 localised_family = get_familyname(ft_face);
1336 if(localised_family && !strcmpW(localised_family, english_family)) {
1337 HeapFree(GetProcessHeap(), 0, localised_family);
1338 localised_family = NULL;
1342 family = NULL;
1343 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1344 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1345 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1346 break;
1347 family = NULL;
1349 if(!family) {
1350 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1351 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1352 list_init(&family->faces);
1353 list_add_tail(&font_list, &family->entry);
1355 if(localised_family) {
1356 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1357 subst->from.name = strdupW(english_family);
1358 subst->from.charset = -1;
1359 subst->to.name = strdupW(localised_family);
1360 subst->to.charset = -1;
1361 add_font_subst(&font_subst_list, subst, 0);
1364 HeapFree(GetProcessHeap(), 0, localised_family);
1365 HeapFree(GetProcessHeap(), 0, english_family);
1367 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1368 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1369 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1371 internal_leading = 0;
1372 memset(&fs, 0, sizeof(fs));
1374 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1375 if(pOS2) {
1376 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1377 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1378 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1379 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1380 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1381 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1382 if(pOS2->version == 0) {
1383 FT_UInt dummy;
1385 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1386 fs.fsCsb[0] |= FS_LATIN1;
1387 else
1388 fs.fsCsb[0] |= FS_SYMBOL;
1391 #ifdef HAVE_FREETYPE_FTWINFNT_H
1392 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1393 CHARSETINFO csi;
1394 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1395 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1396 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1397 fs = csi.fs;
1398 internal_leading = winfnt_header.internal_leading;
1400 #endif
1402 face_elem_ptr = list_head(&family->faces);
1403 while(face_elem_ptr) {
1404 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1405 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1406 if(!strcmpW(face->StyleName, StyleW) &&
1407 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1408 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1409 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1410 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1412 if(fake_family) {
1413 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1414 HeapFree(GetProcessHeap(), 0, StyleW);
1415 pFT_Done_Face(ft_face);
1416 return 1;
1418 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1419 TRACE("Original font is newer so skipping this one\n");
1420 HeapFree(GetProcessHeap(), 0, StyleW);
1421 pFT_Done_Face(ft_face);
1422 return 1;
1423 } else {
1424 TRACE("Replacing original with this one\n");
1425 list_remove(&face->entry);
1426 HeapFree(GetProcessHeap(), 0, face->file);
1427 HeapFree(GetProcessHeap(), 0, face->StyleName);
1428 HeapFree(GetProcessHeap(), 0, face);
1429 break;
1433 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1434 face->cached_enum_data = NULL;
1435 face->StyleName = StyleW;
1436 if (file)
1438 face->file = strdupA(file);
1439 face->font_data_ptr = NULL;
1440 face->font_data_size = 0;
1442 else
1444 face->file = NULL;
1445 face->font_data_ptr = font_data_ptr;
1446 face->font_data_size = font_data_size;
1448 face->face_index = face_index;
1449 face->ntmFlags = 0;
1450 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1451 face->ntmFlags |= NTM_ITALIC;
1452 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1453 face->ntmFlags |= NTM_BOLD;
1454 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1455 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1456 face->family = family;
1457 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1458 face->fs = fs;
1459 memset(&face->fs_links, 0, sizeof(face->fs_links));
1461 if(FT_IS_SCALABLE(ft_face)) {
1462 memset(&face->size, 0, sizeof(face->size));
1463 face->scalable = TRUE;
1464 } else {
1465 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1466 size->height, size->width, size->size >> 6,
1467 size->x_ppem >> 6, size->y_ppem >> 6);
1468 face->size.height = size->height;
1469 face->size.width = size->width;
1470 face->size.size = size->size;
1471 face->size.x_ppem = size->x_ppem;
1472 face->size.y_ppem = size->y_ppem;
1473 face->size.internal_leading = internal_leading;
1474 face->scalable = FALSE;
1477 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1478 tmp_size = 0;
1479 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1481 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1482 face->ntmFlags |= NTM_PS_OPENTYPE;
1485 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1486 face->fs.fsCsb[0], face->fs.fsCsb[1],
1487 face->fs.fsUsb[0], face->fs.fsUsb[1],
1488 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1491 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1492 for(i = 0; i < ft_face->num_charmaps; i++) {
1493 switch(ft_face->charmaps[i]->encoding) {
1494 case FT_ENCODING_UNICODE:
1495 case FT_ENCODING_APPLE_ROMAN:
1496 face->fs.fsCsb[0] |= FS_LATIN1;
1497 break;
1498 case FT_ENCODING_MS_SYMBOL:
1499 face->fs.fsCsb[0] |= FS_SYMBOL;
1500 break;
1501 default:
1502 break;
1507 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1508 have_installed_roman_font = TRUE;
1510 AddFaceToFamily(face, family);
1512 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1514 num_faces = ft_face->num_faces;
1515 pFT_Done_Face(ft_face);
1516 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1517 debugstr_w(StyleW));
1518 } while(num_faces > ++face_index);
1519 return num_faces;
1522 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1524 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1527 static void DumpFontList(void)
1529 Family *family;
1530 Face *face;
1531 struct list *family_elem_ptr, *face_elem_ptr;
1533 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1534 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1535 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1536 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1537 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1538 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1539 if(!face->scalable)
1540 TRACE(" %d", face->size.height);
1541 TRACE("\n");
1544 return;
1547 /***********************************************************
1548 * The replacement list is a way to map an entire font
1549 * family onto another family. For example adding
1551 * [HKCU\Software\Wine\Fonts\Replacements]
1552 * "Wingdings"="Winedings"
1554 * would enumerate the Winedings font both as Winedings and
1555 * Wingdings. However if a real Wingdings font is present the
1556 * replacement does not take place.
1559 static void LoadReplaceList(void)
1561 HKEY hkey;
1562 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1563 LPWSTR value;
1564 LPVOID data;
1565 Family *family;
1566 Face *face;
1567 struct list *family_elem_ptr, *face_elem_ptr;
1568 CHAR familyA[400];
1570 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1571 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1573 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1574 &valuelen, &datalen, NULL, NULL);
1576 valuelen++; /* returned value doesn't include room for '\0' */
1577 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1578 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1580 dlen = datalen;
1581 vlen = valuelen;
1582 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1583 &dlen) == ERROR_SUCCESS) {
1584 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1585 /* "NewName"="Oldname" */
1586 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1588 /* Find the old family and hence all of the font files
1589 in that family */
1590 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1591 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1592 if(!strcmpiW(family->FamilyName, data)) {
1593 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1594 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1595 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1596 debugstr_w(face->StyleName), familyA);
1597 /* Now add a new entry with the new family name */
1598 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1600 break;
1603 /* reset dlen and vlen */
1604 dlen = datalen;
1605 vlen = valuelen;
1607 HeapFree(GetProcessHeap(), 0, data);
1608 HeapFree(GetProcessHeap(), 0, value);
1609 RegCloseKey(hkey);
1613 /*************************************************************
1614 * init_system_links
1616 static BOOL init_system_links(void)
1618 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1619 'W','i','n','d','o','w','s',' ','N','T','\\',
1620 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1621 'S','y','s','t','e','m','L','i','n','k',0};
1622 HKEY hkey;
1623 BOOL ret = FALSE;
1624 DWORD type, max_val, max_data, val_len, data_len, index;
1625 WCHAR *value, *data;
1626 WCHAR *entry, *next;
1627 SYSTEM_LINKS *font_link, *system_font_link;
1628 CHILD_FONT *child_font;
1629 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1630 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1631 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1632 FONTSIGNATURE fs;
1633 Family *family;
1634 Face *face;
1635 FontSubst *psub;
1637 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1639 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1640 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1641 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1642 val_len = max_val + 1;
1643 data_len = max_data;
1644 index = 0;
1645 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1647 TRACE("%s:\n", debugstr_w(value));
1649 memset(&fs, 0, sizeof(fs));
1650 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1651 psub = get_font_subst(&font_subst_list, value, -1);
1652 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1653 list_init(&font_link->links);
1654 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1656 WCHAR *face_name;
1657 CHILD_FONT *child_font;
1659 TRACE("\t%s\n", debugstr_w(entry));
1661 next = entry + strlenW(entry) + 1;
1663 face_name = strchrW(entry, ',');
1664 if(face_name)
1666 *face_name++ = 0;
1667 while(isspaceW(*face_name))
1668 face_name++;
1670 psub = get_font_subst(&font_subst_list, face_name, -1);
1671 if(psub)
1672 face_name = psub->to.name;
1674 face = find_face_from_filename(entry, face_name);
1675 if(!face)
1677 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1678 continue;
1681 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1682 child_font->face = face;
1683 child_font->font = NULL;
1684 fs.fsCsb[0] |= face->fs.fsCsb[0];
1685 fs.fsCsb[1] |= face->fs.fsCsb[1];
1686 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1687 list_add_tail(&font_link->links, &child_font->entry);
1689 family = find_family_from_name(font_link->font_name);
1690 if(family)
1692 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1694 face->fs_links = fs;
1697 list_add_tail(&system_links, &font_link->entry);
1698 val_len = max_val + 1;
1699 data_len = max_data;
1702 HeapFree(GetProcessHeap(), 0, value);
1703 HeapFree(GetProcessHeap(), 0, data);
1704 RegCloseKey(hkey);
1707 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1708 that Tahoma has */
1710 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1711 system_font_link->font_name = strdupW(System);
1712 list_init(&system_font_link->links);
1714 face = find_face_from_filename(tahoma_ttf, Tahoma);
1715 if(face)
1717 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1718 child_font->face = face;
1719 child_font->font = NULL;
1720 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1721 list_add_tail(&system_font_link->links, &child_font->entry);
1723 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1725 if(!strcmpiW(font_link->font_name, Tahoma))
1727 CHILD_FONT *font_link_entry;
1728 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1730 CHILD_FONT *new_child;
1731 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1732 new_child->face = font_link_entry->face;
1733 new_child->font = NULL;
1734 list_add_tail(&system_font_link->links, &new_child->entry);
1736 break;
1739 list_add_tail(&system_links, &system_font_link->entry);
1740 return ret;
1743 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1745 DIR *dir;
1746 struct dirent *dent;
1747 char path[MAX_PATH];
1749 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1751 dir = opendir(dirname);
1752 if(!dir) {
1753 WARN("Can't open directory %s\n", debugstr_a(dirname));
1754 return FALSE;
1756 while((dent = readdir(dir)) != NULL) {
1757 struct stat statbuf;
1759 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1760 continue;
1762 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1764 sprintf(path, "%s/%s", dirname, dent->d_name);
1766 if(stat(path, &statbuf) == -1)
1768 WARN("Can't stat %s\n", debugstr_a(path));
1769 continue;
1771 if(S_ISDIR(statbuf.st_mode))
1772 ReadFontDir(path, external_fonts);
1773 else
1774 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1776 closedir(dir);
1777 return TRUE;
1780 static void load_fontconfig_fonts(void)
1782 #ifdef SONAME_LIBFONTCONFIG
1783 void *fc_handle = NULL;
1784 FcConfig *config;
1785 FcPattern *pat;
1786 FcObjectSet *os;
1787 FcFontSet *fontset;
1788 int i, len;
1789 char *file;
1790 const char *ext;
1792 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1793 if(!fc_handle) {
1794 TRACE("Wine cannot find the fontconfig library (%s).\n",
1795 SONAME_LIBFONTCONFIG);
1796 return;
1798 #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;}
1799 LOAD_FUNCPTR(FcConfigGetCurrent);
1800 LOAD_FUNCPTR(FcFontList);
1801 LOAD_FUNCPTR(FcFontSetDestroy);
1802 LOAD_FUNCPTR(FcInit);
1803 LOAD_FUNCPTR(FcObjectSetAdd);
1804 LOAD_FUNCPTR(FcObjectSetCreate);
1805 LOAD_FUNCPTR(FcObjectSetDestroy);
1806 LOAD_FUNCPTR(FcPatternCreate);
1807 LOAD_FUNCPTR(FcPatternDestroy);
1808 LOAD_FUNCPTR(FcPatternGetBool);
1809 LOAD_FUNCPTR(FcPatternGetString);
1810 #undef LOAD_FUNCPTR
1812 if(!pFcInit()) return;
1814 config = pFcConfigGetCurrent();
1815 pat = pFcPatternCreate();
1816 os = pFcObjectSetCreate();
1817 pFcObjectSetAdd(os, FC_FILE);
1818 pFcObjectSetAdd(os, FC_SCALABLE);
1819 fontset = pFcFontList(config, pat, os);
1820 if(!fontset) return;
1821 for(i = 0; i < fontset->nfont; i++) {
1822 FcBool scalable;
1824 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1825 continue;
1826 TRACE("fontconfig: %s\n", file);
1828 /* We're just interested in OT/TT fonts for now, so this hack just
1829 picks up the scalable fonts without extensions .pf[ab] to save time
1830 loading every other font */
1832 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1834 TRACE("not scalable\n");
1835 continue;
1838 len = strlen( file );
1839 if(len < 4) continue;
1840 ext = &file[ len - 3 ];
1841 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1842 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1844 pFcFontSetDestroy(fontset);
1845 pFcObjectSetDestroy(os);
1846 pFcPatternDestroy(pat);
1847 sym_not_found:
1848 #endif
1849 return;
1852 static BOOL load_font_from_data_dir(LPCWSTR file)
1854 BOOL ret = FALSE;
1855 const char *data_dir = wine_get_data_dir();
1857 if (!data_dir) data_dir = wine_get_build_dir();
1859 if (data_dir)
1861 INT len;
1862 char *unix_name;
1864 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1866 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1868 strcpy(unix_name, data_dir);
1869 strcat(unix_name, "/fonts/");
1871 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1873 EnterCriticalSection( &freetype_cs );
1874 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1875 LeaveCriticalSection( &freetype_cs );
1876 HeapFree(GetProcessHeap(), 0, unix_name);
1878 return ret;
1881 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1883 static const WCHAR slashW[] = {'\\','\0'};
1884 BOOL ret = FALSE;
1885 WCHAR windowsdir[MAX_PATH];
1886 char *unixname;
1888 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1889 strcatW(windowsdir, fontsW);
1890 strcatW(windowsdir, slashW);
1891 strcatW(windowsdir, file);
1892 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1893 EnterCriticalSection( &freetype_cs );
1894 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1895 LeaveCriticalSection( &freetype_cs );
1896 HeapFree(GetProcessHeap(), 0, unixname);
1898 return ret;
1901 static void load_system_fonts(void)
1903 HKEY hkey;
1904 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1905 const WCHAR * const *value;
1906 DWORD dlen, type;
1907 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1908 char *unixname;
1910 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1911 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1912 strcatW(windowsdir, fontsW);
1913 for(value = SystemFontValues; *value; value++) {
1914 dlen = sizeof(data);
1915 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1916 type == REG_SZ) {
1917 BOOL added = FALSE;
1919 sprintfW(pathW, fmtW, windowsdir, data);
1920 if((unixname = wine_get_unix_file_name(pathW))) {
1921 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1922 HeapFree(GetProcessHeap(), 0, unixname);
1924 if (!added)
1925 load_font_from_data_dir(data);
1928 RegCloseKey(hkey);
1932 /*************************************************************
1934 * This adds registry entries for any externally loaded fonts
1935 * (fonts from fontconfig or FontDirs). It also deletes entries
1936 * of no longer existing fonts.
1939 static void update_reg_entries(void)
1941 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1942 LPWSTR valueW;
1943 DWORD len, len_fam;
1944 Family *family;
1945 Face *face;
1946 struct list *family_elem_ptr, *face_elem_ptr;
1947 WCHAR *file;
1948 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1949 static const WCHAR spaceW[] = {' ', '\0'};
1950 char *path;
1952 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1953 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1954 ERR("Can't create Windows font reg key\n");
1955 goto end;
1958 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1959 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1960 ERR("Can't create Windows font reg key\n");
1961 goto end;
1964 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1965 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1966 ERR("Can't create external font reg key\n");
1967 goto end;
1970 /* enumerate the fonts and add external ones to the two keys */
1972 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1973 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1974 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1975 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1976 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1977 if(!face->external) continue;
1978 len = len_fam;
1979 if (!(face->ntmFlags & NTM_REGULAR))
1980 len = len_fam + strlenW(face->StyleName) + 1;
1981 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1982 strcpyW(valueW, family->FamilyName);
1983 if(len != len_fam) {
1984 strcatW(valueW, spaceW);
1985 strcatW(valueW, face->StyleName);
1987 strcatW(valueW, TrueType);
1989 file = wine_get_dos_file_name(face->file);
1990 if(file)
1991 len = strlenW(file) + 1;
1992 else
1994 if((path = strrchr(face->file, '/')) == NULL)
1995 path = face->file;
1996 else
1997 path++;
1998 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2000 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2001 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2003 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2004 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2005 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2007 HeapFree(GetProcessHeap(), 0, file);
2008 HeapFree(GetProcessHeap(), 0, valueW);
2011 end:
2012 if(external_key) RegCloseKey(external_key);
2013 if(win9x_key) RegCloseKey(win9x_key);
2014 if(winnt_key) RegCloseKey(winnt_key);
2015 return;
2018 static void delete_external_font_keys(void)
2020 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2021 DWORD dlen, vlen, datalen, valuelen, i, type;
2022 LPWSTR valueW;
2023 LPVOID data;
2025 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2026 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2027 ERR("Can't create Windows font reg key\n");
2028 goto end;
2031 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2032 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2033 ERR("Can't create Windows font reg key\n");
2034 goto end;
2037 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2038 ERR("Can't create external font reg key\n");
2039 goto end;
2042 /* Delete all external fonts added last time */
2044 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2045 &valuelen, &datalen, NULL, NULL);
2046 valuelen++; /* returned value doesn't include room for '\0' */
2047 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2048 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2050 dlen = datalen * sizeof(WCHAR);
2051 vlen = valuelen;
2052 i = 0;
2053 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2054 &dlen) == ERROR_SUCCESS) {
2056 RegDeleteValueW(winnt_key, valueW);
2057 RegDeleteValueW(win9x_key, valueW);
2058 /* reset dlen and vlen */
2059 dlen = datalen;
2060 vlen = valuelen;
2062 HeapFree(GetProcessHeap(), 0, data);
2063 HeapFree(GetProcessHeap(), 0, valueW);
2065 /* Delete the old external fonts key */
2066 RegCloseKey(external_key);
2067 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2069 end:
2070 if(win9x_key) RegCloseKey(win9x_key);
2071 if(winnt_key) RegCloseKey(winnt_key);
2074 /*************************************************************
2075 * WineEngAddFontResourceEx
2078 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2080 INT ret = 0;
2081 if (ft_handle) /* do it only if we have freetype up and running */
2083 char *unixname;
2085 if(flags)
2086 FIXME("Ignoring flags %x\n", flags);
2088 if((unixname = wine_get_unix_file_name(file)))
2090 EnterCriticalSection( &freetype_cs );
2091 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2092 LeaveCriticalSection( &freetype_cs );
2093 HeapFree(GetProcessHeap(), 0, unixname);
2095 if (!ret && !strchrW(file, '\\')) {
2096 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2097 ret = load_font_from_winfonts_dir(file);
2098 if (!ret) {
2099 /* Try in datadir/fonts (or builddir/fonts),
2100 * needed for Magic the Gathering Online
2102 ret = load_font_from_data_dir(file);
2106 return ret;
2109 /*************************************************************
2110 * WineEngAddFontMemResourceEx
2113 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2115 if (ft_handle) /* do it only if we have freetype up and running */
2117 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2119 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2120 memcpy(pFontCopy, pbFont, cbFont);
2122 EnterCriticalSection( &freetype_cs );
2123 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2124 LeaveCriticalSection( &freetype_cs );
2126 if (*pcFonts == 0)
2128 TRACE("AddFontToList failed\n");
2129 HeapFree(GetProcessHeap(), 0, pFontCopy);
2130 return NULL;
2132 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2133 * For now return something unique but quite random
2135 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2136 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2139 *pcFonts = 0;
2140 return 0;
2143 /*************************************************************
2144 * WineEngRemoveFontResourceEx
2147 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2149 FIXME(":stub\n");
2150 return TRUE;
2153 static const struct nls_update_font_list
2155 UINT ansi_cp, oem_cp;
2156 const char *oem, *fixed, *system;
2157 const char *courier, *serif, *small, *sserif;
2158 /* these are for font substitutes */
2159 const char *shelldlg, *tmsrmn;
2160 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2161 *helv_0, *tmsrmn_0;
2162 const struct subst
2164 const char *from, *to;
2165 } arial_0, courier_new_0, times_new_roman_0;
2166 } nls_update_font_list[] =
2168 /* Latin 1 (United States) */
2169 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2170 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2171 "Tahoma","Times New Roman",
2172 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2173 { 0 }, { 0 }, { 0 }
2175 /* Latin 1 (Multilingual) */
2176 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2177 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2178 "Tahoma","Times New Roman", /* FIXME unverified */
2179 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2180 { 0 }, { 0 }, { 0 }
2182 /* Eastern Europe */
2183 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2184 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2185 "Tahoma","Times New Roman", /* FIXME unverified */
2186 "Fixedsys,238", "System,238",
2187 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2188 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2189 { "Arial CE,0", "Arial,238" },
2190 { "Courier New CE,0", "Courier New,238" },
2191 { "Times New Roman CE,0", "Times New Roman,238" }
2193 /* Cyrillic */
2194 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2195 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2196 "Tahoma","Times New Roman", /* FIXME unverified */
2197 "Fixedsys,204", "System,204",
2198 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2199 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2200 { "Arial Cyr,0", "Arial,204" },
2201 { "Courier New Cyr,0", "Courier New,204" },
2202 { "Times New Roman Cyr,0", "Times New Roman,204" }
2204 /* Greek */
2205 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2206 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2207 "Tahoma","Times New Roman", /* FIXME unverified */
2208 "Fixedsys,161", "System,161",
2209 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2210 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2211 { "Arial Greek,0", "Arial,161" },
2212 { "Courier New Greek,0", "Courier New,161" },
2213 { "Times New Roman Greek,0", "Times New Roman,161" }
2215 /* Turkish */
2216 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2217 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2218 "Tahoma","Times New Roman", /* FIXME unverified */
2219 "Fixedsys,162", "System,162",
2220 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2221 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2222 { "Arial Tur,0", "Arial,162" },
2223 { "Courier New Tur,0", "Courier New,162" },
2224 { "Times New Roman Tur,0", "Times New Roman,162" }
2226 /* Hebrew */
2227 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2228 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2229 "Tahoma","Times New Roman", /* FIXME unverified */
2230 "Fixedsys,177", "System,177",
2231 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2232 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2233 { 0 }, { 0 }, { 0 }
2235 /* Arabic */
2236 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2237 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,178", "System,178",
2240 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2241 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2242 { 0 }, { 0 }, { 0 }
2244 /* Baltic */
2245 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2246 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2247 "Tahoma","Times New Roman", /* FIXME unverified */
2248 "Fixedsys,186", "System,186",
2249 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2250 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2251 { "Arial Baltic,0", "Arial,186" },
2252 { "Courier New Baltic,0", "Courier New,186" },
2253 { "Times New Roman Baltic,0", "Times New Roman,186" }
2255 /* Vietnamese */
2256 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2257 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2258 "Tahoma","Times New Roman", /* FIXME unverified */
2259 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2260 { 0 }, { 0 }, { 0 }
2262 /* Thai */
2263 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2264 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2265 "Tahoma","Times New Roman", /* FIXME unverified */
2266 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2267 { 0 }, { 0 }, { 0 }
2269 /* Japanese */
2270 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2271 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2272 "MS UI Gothic","MS Serif",
2273 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2274 { 0 }, { 0 }, { 0 }
2276 /* Chinese Simplified */
2277 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2278 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2279 "Tahoma", "Times New Roman", /* FIXME unverified */
2280 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2281 { 0 }, { 0 }, { 0 }
2283 /* Korean */
2284 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2285 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2286 "Gulim", "Batang",
2287 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2288 { 0 }, { 0 }, { 0 }
2290 /* Chinese Traditional */
2291 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2292 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2293 "PMingLiU", "MingLiU",
2294 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2295 { 0 }, { 0 }, { 0 }
2299 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2301 return ( ansi_cp == 932 /* CP932 for Japanese */
2302 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2303 || ansi_cp == 949 /* CP949 for Korean */
2304 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2307 static inline HKEY create_fonts_NT_registry_key(void)
2309 HKEY hkey = 0;
2311 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2312 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2313 return hkey;
2316 static inline HKEY create_fonts_9x_registry_key(void)
2318 HKEY hkey = 0;
2320 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2321 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2322 return hkey;
2325 static inline HKEY create_config_fonts_registry_key(void)
2327 HKEY hkey = 0;
2329 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2330 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2331 return hkey;
2334 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2336 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2337 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2338 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2339 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2342 static void set_value_key(HKEY hkey, const char *name, const char *value)
2344 if (value)
2345 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2346 else if (name)
2347 RegDeleteValueA(hkey, name);
2350 static void update_font_info(void)
2352 char buf[40], cpbuf[40];
2353 DWORD len, type;
2354 HKEY hkey = 0;
2355 UINT i, ansi_cp = 0, oem_cp = 0;
2356 BOOL done = FALSE;
2358 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2359 return;
2361 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2362 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2363 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2364 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2365 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2367 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2368 if (is_dbcs_ansi_cp(ansi_cp))
2369 use_default_fallback = TRUE;
2371 len = sizeof(buf);
2372 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2374 if (!strcmp( buf, cpbuf )) /* already set correctly */
2376 RegCloseKey(hkey);
2377 return;
2379 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2381 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2383 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2384 RegCloseKey(hkey);
2386 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2388 HKEY hkey;
2390 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2391 nls_update_font_list[i].oem_cp == oem_cp)
2393 hkey = create_config_fonts_registry_key();
2394 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2395 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2396 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2397 RegCloseKey(hkey);
2399 hkey = create_fonts_NT_registry_key();
2400 add_font_list(hkey, &nls_update_font_list[i]);
2401 RegCloseKey(hkey);
2403 hkey = create_fonts_9x_registry_key();
2404 add_font_list(hkey, &nls_update_font_list[i]);
2405 RegCloseKey(hkey);
2407 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2409 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2410 strlen(nls_update_font_list[i].shelldlg)+1);
2411 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2412 strlen(nls_update_font_list[i].tmsrmn)+1);
2414 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2415 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2416 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2417 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2418 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2419 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2420 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2421 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2423 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2424 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2425 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2427 RegCloseKey(hkey);
2429 done = TRUE;
2431 else
2433 /* Delete the FontSubstitutes from other locales */
2434 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2436 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2437 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2438 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2439 RegCloseKey(hkey);
2443 if (!done)
2444 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2448 static BOOL init_freetype(void)
2450 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2451 if(!ft_handle) {
2452 WINE_MESSAGE(
2453 "Wine cannot find the FreeType font library. To enable Wine to\n"
2454 "use TrueType fonts please install a version of FreeType greater than\n"
2455 "or equal to 2.0.5.\n"
2456 "http://www.freetype.org\n");
2457 return FALSE;
2460 #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;}
2462 LOAD_FUNCPTR(FT_Vector_Unit)
2463 LOAD_FUNCPTR(FT_Done_Face)
2464 LOAD_FUNCPTR(FT_Get_Char_Index)
2465 LOAD_FUNCPTR(FT_Get_Module)
2466 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2467 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2468 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2469 LOAD_FUNCPTR(FT_Init_FreeType)
2470 LOAD_FUNCPTR(FT_Load_Glyph)
2471 LOAD_FUNCPTR(FT_Matrix_Multiply)
2472 #ifndef FT_MULFIX_INLINED
2473 LOAD_FUNCPTR(FT_MulFix)
2474 #endif
2475 LOAD_FUNCPTR(FT_New_Face)
2476 LOAD_FUNCPTR(FT_New_Memory_Face)
2477 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2478 LOAD_FUNCPTR(FT_Outline_Transform)
2479 LOAD_FUNCPTR(FT_Outline_Translate)
2480 LOAD_FUNCPTR(FT_Select_Charmap)
2481 LOAD_FUNCPTR(FT_Set_Charmap)
2482 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2483 LOAD_FUNCPTR(FT_Vector_Transform)
2485 #undef LOAD_FUNCPTR
2486 /* Don't warn if these ones are missing */
2487 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2488 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2489 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2490 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2491 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2492 #ifdef HAVE_FREETYPE_FTWINFNT_H
2493 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2494 #endif
2495 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2496 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2497 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2498 <= 2.0.3 has FT_Sqrt64 */
2499 goto sym_not_found;
2502 if(pFT_Init_FreeType(&library) != 0) {
2503 ERR("Can't init FreeType library\n");
2504 wine_dlclose(ft_handle, NULL, 0);
2505 ft_handle = NULL;
2506 return FALSE;
2508 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2509 if (pFT_Library_Version)
2510 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2512 if (FT_Version.major<=0)
2514 FT_Version.major=2;
2515 FT_Version.minor=0;
2516 FT_Version.patch=5;
2518 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2519 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2520 ((FT_Version.minor << 8) & 0x00ff00) |
2521 ((FT_Version.patch ) & 0x0000ff);
2523 return TRUE;
2525 sym_not_found:
2526 WINE_MESSAGE(
2527 "Wine cannot find certain functions that it needs inside the FreeType\n"
2528 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2529 "FreeType to at least version 2.0.5.\n"
2530 "http://www.freetype.org\n");
2531 wine_dlclose(ft_handle, NULL, 0);
2532 ft_handle = NULL;
2533 return FALSE;
2536 /*************************************************************
2537 * WineEngInit
2539 * Initialize FreeType library and create a list of available faces
2541 BOOL WineEngInit(void)
2543 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2544 static const WCHAR pathW[] = {'P','a','t','h',0};
2545 HKEY hkey;
2546 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2547 LPVOID data;
2548 WCHAR windowsdir[MAX_PATH];
2549 char *unixname;
2550 HANDLE font_mutex;
2551 const char *data_dir;
2553 TRACE("\n");
2555 /* update locale dependent font info in registry */
2556 update_font_info();
2558 if(!init_freetype()) return FALSE;
2560 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2561 ERR("Failed to create font mutex\n");
2562 return FALSE;
2564 WaitForSingleObject(font_mutex, INFINITE);
2566 delete_external_font_keys();
2568 /* load the system bitmap fonts */
2569 load_system_fonts();
2571 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2572 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2573 strcatW(windowsdir, fontsW);
2574 if((unixname = wine_get_unix_file_name(windowsdir)))
2576 ReadFontDir(unixname, FALSE);
2577 HeapFree(GetProcessHeap(), 0, unixname);
2580 /* load the system truetype fonts */
2581 data_dir = wine_get_data_dir();
2582 if (!data_dir) data_dir = wine_get_build_dir();
2583 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2584 strcpy(unixname, data_dir);
2585 strcat(unixname, "/fonts/");
2586 ReadFontDir(unixname, TRUE);
2587 HeapFree(GetProcessHeap(), 0, unixname);
2590 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2591 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2592 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2593 will skip these. */
2594 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2595 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2596 &hkey) == ERROR_SUCCESS) {
2597 LPWSTR valueW;
2598 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2599 &valuelen, &datalen, NULL, NULL);
2601 valuelen++; /* returned value doesn't include room for '\0' */
2602 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2603 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2604 if (valueW && data)
2606 dlen = datalen * sizeof(WCHAR);
2607 vlen = valuelen;
2608 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2609 &dlen) == ERROR_SUCCESS) {
2610 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2612 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2614 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2615 HeapFree(GetProcessHeap(), 0, unixname);
2618 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2620 WCHAR pathW[MAX_PATH];
2621 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2622 BOOL added = FALSE;
2624 sprintfW(pathW, fmtW, windowsdir, data);
2625 if((unixname = wine_get_unix_file_name(pathW)))
2627 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2628 HeapFree(GetProcessHeap(), 0, unixname);
2630 if (!added)
2631 load_font_from_data_dir(data);
2633 /* reset dlen and vlen */
2634 dlen = datalen;
2635 vlen = valuelen;
2638 HeapFree(GetProcessHeap(), 0, data);
2639 HeapFree(GetProcessHeap(), 0, valueW);
2640 RegCloseKey(hkey);
2643 load_fontconfig_fonts();
2645 /* then look in any directories that we've specified in the config file */
2646 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2647 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2649 DWORD len;
2650 LPWSTR valueW;
2651 LPSTR valueA, ptr;
2653 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2655 len += sizeof(WCHAR);
2656 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2657 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2659 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2660 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2661 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2662 TRACE( "got font path %s\n", debugstr_a(valueA) );
2663 ptr = valueA;
2664 while (ptr)
2666 LPSTR next = strchr( ptr, ':' );
2667 if (next) *next++ = 0;
2668 ReadFontDir( ptr, TRUE );
2669 ptr = next;
2671 HeapFree( GetProcessHeap(), 0, valueA );
2673 HeapFree( GetProcessHeap(), 0, valueW );
2675 RegCloseKey(hkey);
2678 DumpFontList();
2679 LoadSubstList();
2680 DumpSubstList();
2681 LoadReplaceList();
2682 update_reg_entries();
2684 init_system_links();
2686 ReleaseMutex(font_mutex);
2687 return TRUE;
2691 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2693 TT_OS2 *pOS2;
2694 TT_HoriHeader *pHori;
2696 LONG ppem;
2698 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2699 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2701 if(height == 0) height = 16;
2703 /* Calc. height of EM square:
2705 * For +ve lfHeight we have
2706 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2707 * Re-arranging gives:
2708 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2710 * For -ve lfHeight we have
2711 * |lfHeight| = ppem
2712 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2713 * with il = winAscent + winDescent - units_per_em]
2717 if(height > 0) {
2718 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2719 ppem = MulDiv(ft_face->units_per_EM, height,
2720 pHori->Ascender - pHori->Descender);
2721 else
2722 ppem = MulDiv(ft_face->units_per_EM, height,
2723 pOS2->usWinAscent + pOS2->usWinDescent);
2725 else
2726 ppem = -height;
2728 return ppem;
2731 static struct font_mapping *map_font_file( const char *name )
2733 struct font_mapping *mapping;
2734 struct stat st;
2735 int fd;
2737 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2738 if (fstat( fd, &st ) == -1) goto error;
2740 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2742 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2744 mapping->refcount++;
2745 close( fd );
2746 return mapping;
2749 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2750 goto error;
2752 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2753 close( fd );
2755 if (mapping->data == MAP_FAILED)
2757 HeapFree( GetProcessHeap(), 0, mapping );
2758 return NULL;
2760 mapping->refcount = 1;
2761 mapping->dev = st.st_dev;
2762 mapping->ino = st.st_ino;
2763 mapping->size = st.st_size;
2764 list_add_tail( &mappings_list, &mapping->entry );
2765 return mapping;
2767 error:
2768 close( fd );
2769 return NULL;
2772 static void unmap_font_file( struct font_mapping *mapping )
2774 if (!--mapping->refcount)
2776 list_remove( &mapping->entry );
2777 munmap( mapping->data, mapping->size );
2778 HeapFree( GetProcessHeap(), 0, mapping );
2782 static LONG load_VDMX(GdiFont*, LONG);
2784 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2786 FT_Error err;
2787 FT_Face ft_face;
2788 void *data_ptr;
2789 DWORD data_size;
2791 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2793 if (face->file)
2795 if (!(font->mapping = map_font_file( face->file )))
2797 WARN("failed to map %s\n", debugstr_a(face->file));
2798 return 0;
2800 data_ptr = font->mapping->data;
2801 data_size = font->mapping->size;
2803 else
2805 data_ptr = face->font_data_ptr;
2806 data_size = face->font_data_size;
2809 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2810 if(err) {
2811 ERR("FT_New_Face rets %d\n", err);
2812 return 0;
2815 /* set it here, as load_VDMX needs it */
2816 font->ft_face = ft_face;
2818 if(FT_IS_SCALABLE(ft_face)) {
2819 /* load the VDMX table if we have one */
2820 font->ppem = load_VDMX(font, height);
2821 if(font->ppem == 0)
2822 font->ppem = calc_ppem_for_height(ft_face, height);
2823 TRACE("height %d => ppem %d\n", height, font->ppem);
2825 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2826 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2827 } else {
2828 font->ppem = height;
2829 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2830 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2832 return ft_face;
2836 static int get_nearest_charset(Face *face, int *cp)
2838 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2839 a single face with the requested charset. The idea is to check if
2840 the selected font supports the current ANSI codepage, if it does
2841 return the corresponding charset, else return the first charset */
2843 CHARSETINFO csi;
2844 int acp = GetACP(), i;
2845 DWORD fs0;
2847 *cp = acp;
2848 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2849 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2850 return csi.ciCharset;
2852 for(i = 0; i < 32; i++) {
2853 fs0 = 1L << i;
2854 if(face->fs.fsCsb[0] & fs0) {
2855 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2856 *cp = csi.ciACP;
2857 return csi.ciCharset;
2859 else
2860 FIXME("TCI failing on %x\n", fs0);
2864 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2865 face->fs.fsCsb[0], face->file);
2866 *cp = acp;
2867 return DEFAULT_CHARSET;
2870 static GdiFont *alloc_font(void)
2872 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2873 ret->gmsize = 1;
2874 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2875 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2876 ret->potm = NULL;
2877 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2878 ret->total_kern_pairs = (DWORD)-1;
2879 ret->kern_pairs = NULL;
2880 list_init(&ret->hfontlist);
2881 list_init(&ret->child_fonts);
2882 return ret;
2885 static void free_font(GdiFont *font)
2887 struct list *cursor, *cursor2;
2888 DWORD i;
2890 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2892 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2893 struct list *first_hfont;
2894 HFONTLIST *hfontlist;
2895 list_remove(cursor);
2896 if(child->font)
2898 first_hfont = list_head(&child->font->hfontlist);
2899 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2900 DeleteObject(hfontlist->hfont);
2901 HeapFree(GetProcessHeap(), 0, hfontlist);
2902 free_font(child->font);
2904 HeapFree(GetProcessHeap(), 0, child);
2907 if (font->ft_face) pFT_Done_Face(font->ft_face);
2908 if (font->mapping) unmap_font_file( font->mapping );
2909 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2910 HeapFree(GetProcessHeap(), 0, font->potm);
2911 HeapFree(GetProcessHeap(), 0, font->name);
2912 for (i = 0; i < font->gmsize; i++)
2913 HeapFree(GetProcessHeap(),0,font->gm[i]);
2914 HeapFree(GetProcessHeap(), 0, font->gm);
2915 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2916 HeapFree(GetProcessHeap(), 0, font);
2920 /*************************************************************
2921 * load_VDMX
2923 * load the vdmx entry for the specified height
2926 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2927 ( ( (FT_ULong)_x4 << 24 ) | \
2928 ( (FT_ULong)_x3 << 16 ) | \
2929 ( (FT_ULong)_x2 << 8 ) | \
2930 (FT_ULong)_x1 )
2932 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2934 typedef struct {
2935 BYTE bCharSet;
2936 BYTE xRatio;
2937 BYTE yStartRatio;
2938 BYTE yEndRatio;
2939 } Ratios;
2941 typedef struct {
2942 WORD recs;
2943 BYTE startsz;
2944 BYTE endsz;
2945 } VDMX_group;
2947 static LONG load_VDMX(GdiFont *font, LONG height)
2949 WORD hdr[3], tmp;
2950 VDMX_group group;
2951 BYTE devXRatio, devYRatio;
2952 USHORT numRecs, numRatios;
2953 DWORD result, offset = -1;
2954 LONG ppem = 0;
2955 int i;
2957 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2959 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2960 return ppem;
2962 /* FIXME: need the real device aspect ratio */
2963 devXRatio = 1;
2964 devYRatio = 1;
2966 numRecs = GET_BE_WORD(hdr[1]);
2967 numRatios = GET_BE_WORD(hdr[2]);
2969 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2970 for(i = 0; i < numRatios; i++) {
2971 Ratios ratio;
2973 offset = (3 * 2) + (i * sizeof(Ratios));
2974 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2975 offset = -1;
2977 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2979 if((ratio.xRatio == 0 &&
2980 ratio.yStartRatio == 0 &&
2981 ratio.yEndRatio == 0) ||
2982 (devXRatio == ratio.xRatio &&
2983 devYRatio >= ratio.yStartRatio &&
2984 devYRatio <= ratio.yEndRatio))
2986 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2987 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2988 offset = GET_BE_WORD(tmp);
2989 break;
2993 if(offset == -1) {
2994 FIXME("No suitable ratio found\n");
2995 return ppem;
2998 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2999 USHORT recs;
3000 BYTE startsz, endsz;
3001 WORD *vTable;
3003 recs = GET_BE_WORD(group.recs);
3004 startsz = group.startsz;
3005 endsz = group.endsz;
3007 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3009 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3010 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3011 if(result == GDI_ERROR) {
3012 FIXME("Failed to retrieve vTable\n");
3013 goto end;
3016 if(height > 0) {
3017 for(i = 0; i < recs; i++) {
3018 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3019 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3020 ppem = GET_BE_WORD(vTable[i * 3]);
3022 if(yMax + -yMin == height) {
3023 font->yMax = yMax;
3024 font->yMin = yMin;
3025 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3026 break;
3028 if(yMax + -yMin > height) {
3029 if(--i < 0) {
3030 ppem = 0;
3031 goto end; /* failed */
3033 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3034 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3035 ppem = GET_BE_WORD(vTable[i * 3]);
3036 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3037 break;
3040 if(!font->yMax) {
3041 ppem = 0;
3042 TRACE("ppem not found for height %d\n", height);
3044 } else {
3045 ppem = -height;
3046 if(ppem < startsz || ppem > endsz)
3047 goto end;
3049 for(i = 0; i < recs; i++) {
3050 USHORT yPelHeight;
3051 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3053 if(yPelHeight > ppem)
3054 break; /* failed */
3056 if(yPelHeight == ppem) {
3057 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3058 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3059 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3060 break;
3064 end:
3065 HeapFree(GetProcessHeap(), 0, vTable);
3068 return ppem;
3071 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3073 if(font->font_desc.hash != fd->hash) return TRUE;
3074 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3075 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3076 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3077 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3080 static void calc_hash(FONT_DESC *pfd)
3082 DWORD hash = 0, *ptr, two_chars;
3083 WORD *pwc;
3084 unsigned int i;
3086 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3087 hash ^= *ptr;
3088 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3089 hash ^= *ptr;
3090 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3091 two_chars = *ptr;
3092 pwc = (WCHAR *)&two_chars;
3093 if(!*pwc) break;
3094 *pwc = toupperW(*pwc);
3095 pwc++;
3096 *pwc = toupperW(*pwc);
3097 hash ^= two_chars;
3098 if(!*pwc) break;
3100 hash ^= !pfd->can_use_bitmap;
3101 pfd->hash = hash;
3102 return;
3105 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3107 GdiFont *ret;
3108 FONT_DESC fd;
3109 HFONTLIST *hflist;
3110 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3112 fd.lf = *plf;
3113 fd.matrix = *pmat;
3114 fd.can_use_bitmap = can_use_bitmap;
3115 calc_hash(&fd);
3117 /* try the child list */
3118 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3119 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3120 if(!fontcmp(ret, &fd)) {
3121 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3122 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3123 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3124 if(hflist->hfont == hfont)
3125 return ret;
3130 /* try the in-use list */
3131 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3132 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3133 if(!fontcmp(ret, &fd)) {
3134 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3135 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3136 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3137 if(hflist->hfont == hfont)
3138 return ret;
3140 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3141 hflist->hfont = hfont;
3142 list_add_head(&ret->hfontlist, &hflist->entry);
3143 return ret;
3147 /* then the unused list */
3148 font_elem_ptr = list_head(&unused_gdi_font_list);
3149 while(font_elem_ptr) {
3150 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3151 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3152 if(!fontcmp(ret, &fd)) {
3153 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3154 assert(list_empty(&ret->hfontlist));
3155 TRACE("Found %p in unused list\n", ret);
3156 list_remove(&ret->entry);
3157 list_add_head(&gdi_font_list, &ret->entry);
3158 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3159 hflist->hfont = hfont;
3160 list_add_head(&ret->hfontlist, &hflist->entry);
3161 return ret;
3164 return NULL;
3167 static void add_to_cache(GdiFont *font)
3169 static DWORD cache_num = 1;
3171 font->cache_num = cache_num++;
3172 list_add_head(&gdi_font_list, &font->entry);
3175 /*************************************************************
3176 * create_child_font_list
3178 static BOOL create_child_font_list(GdiFont *font)
3180 BOOL ret = FALSE;
3181 SYSTEM_LINKS *font_link;
3182 CHILD_FONT *font_link_entry, *new_child;
3184 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3186 if(!strcmpW(font_link->font_name, font->name))
3188 TRACE("found entry in system list\n");
3189 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3191 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3192 new_child->face = font_link_entry->face;
3193 new_child->font = NULL;
3194 list_add_tail(&font->child_fonts, &new_child->entry);
3195 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3197 ret = TRUE;
3198 break;
3202 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3203 * Sans Serif. This is how asian windows get default fallbacks for fonts
3205 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3206 font->charset != OEM_CHARSET &&
3207 strcmpW(font->name,szDefaultFallbackLink) != 0)
3208 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3210 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3212 TRACE("found entry in default fallback list\n");
3213 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3215 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3216 new_child->face = font_link_entry->face;
3217 new_child->font = NULL;
3218 list_add_tail(&font->child_fonts, &new_child->entry);
3219 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3221 ret = TRUE;
3222 break;
3226 return ret;
3229 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3231 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3233 if (pFT_Set_Charmap)
3235 FT_Int i;
3236 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3238 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3240 for (i = 0; i < ft_face->num_charmaps; i++)
3242 if (ft_face->charmaps[i]->encoding == encoding)
3244 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3245 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3247 switch (ft_face->charmaps[i]->platform_id)
3249 default:
3250 cmap_def = ft_face->charmaps[i];
3251 break;
3252 case 0: /* Apple Unicode */
3253 cmap0 = ft_face->charmaps[i];
3254 break;
3255 case 1: /* Macintosh */
3256 cmap1 = ft_face->charmaps[i];
3257 break;
3258 case 2: /* ISO */
3259 cmap2 = ft_face->charmaps[i];
3260 break;
3261 case 3: /* Microsoft */
3262 cmap3 = ft_face->charmaps[i];
3263 break;
3267 if (cmap3) /* prefer Microsoft cmap table */
3268 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3269 else if (cmap1)
3270 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3271 else if (cmap2)
3272 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3273 else if (cmap0)
3274 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3275 else if (cmap_def)
3276 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3278 return ft_err == FT_Err_Ok;
3281 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3284 /*************************************************************
3285 * WineEngCreateFontInstance
3288 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3290 GdiFont *ret;
3291 Face *face, *best, *best_bitmap;
3292 Family *family, *last_resort_family;
3293 struct list *family_elem_ptr, *face_elem_ptr;
3294 INT height, width = 0;
3295 unsigned int score = 0, new_score;
3296 signed int diff = 0, newdiff;
3297 BOOL bd, it, can_use_bitmap;
3298 LOGFONTW lf;
3299 CHARSETINFO csi;
3300 HFONTLIST *hflist;
3301 FMAT2 dcmat;
3302 FontSubst *psub = NULL;
3304 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3305 lf.lfWidth = abs(lf.lfWidth);
3307 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3309 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3310 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3311 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3312 lf.lfEscapement);
3314 if(dc->GraphicsMode == GM_ADVANCED)
3315 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3316 else
3318 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3319 font scaling abilities. */
3320 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3321 dcmat.eM21 = dcmat.eM12 = 0;
3324 /* Try to avoid not necessary glyph transformations */
3325 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3327 lf.lfHeight *= fabs(dcmat.eM11);
3328 lf.lfWidth *= fabs(dcmat.eM11);
3329 dcmat.eM11 = dcmat.eM22 = 1.0;
3332 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3333 dcmat.eM21, dcmat.eM22);
3335 EnterCriticalSection( &freetype_cs );
3337 /* check the cache first */
3338 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3339 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3340 LeaveCriticalSection( &freetype_cs );
3341 return ret;
3344 TRACE("not in cache\n");
3345 if(list_empty(&font_list)) /* No fonts installed */
3347 TRACE("No fonts installed\n");
3348 LeaveCriticalSection( &freetype_cs );
3349 return NULL;
3351 if(!have_installed_roman_font)
3353 TRACE("No roman font installed\n");
3354 LeaveCriticalSection( &freetype_cs );
3355 return NULL;
3358 ret = alloc_font();
3360 ret->font_desc.matrix = dcmat;
3361 ret->font_desc.lf = lf;
3362 ret->font_desc.can_use_bitmap = can_use_bitmap;
3363 calc_hash(&ret->font_desc);
3364 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3365 hflist->hfont = hfont;
3366 list_add_head(&ret->hfontlist, &hflist->entry);
3368 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3369 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3370 original value lfCharSet. Note this is a special case for
3371 Symbol and doesn't happen at least for "Wingdings*" */
3373 if(!strcmpiW(lf.lfFaceName, SymbolW))
3374 lf.lfCharSet = SYMBOL_CHARSET;
3376 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3377 switch(lf.lfCharSet) {
3378 case DEFAULT_CHARSET:
3379 csi.fs.fsCsb[0] = 0;
3380 break;
3381 default:
3382 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3383 csi.fs.fsCsb[0] = 0;
3384 break;
3388 family = NULL;
3389 if(lf.lfFaceName[0] != '\0') {
3390 SYSTEM_LINKS *font_link;
3391 CHILD_FONT *font_link_entry;
3392 LPWSTR FaceName = lf.lfFaceName;
3395 * Check for a leading '@' this signals that the font is being
3396 * requested in tategaki mode (vertical writing substitution) but
3397 * does not affect the fontface that is to be selected.
3399 if (lf.lfFaceName[0]=='@')
3400 FaceName = &lf.lfFaceName[1];
3402 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3404 if(psub) {
3405 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3406 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3407 if (psub->to.charset != -1)
3408 lf.lfCharSet = psub->to.charset;
3411 /* We want a match on name and charset or just name if
3412 charset was DEFAULT_CHARSET. If the latter then
3413 we fixup the returned charset later in get_nearest_charset
3414 where we'll either use the charset of the current ansi codepage
3415 or if that's unavailable the first charset that the font supports.
3417 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3418 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3419 if (!strcmpiW(family->FamilyName, FaceName) ||
3420 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3422 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3423 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3424 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3425 if(face->scalable || can_use_bitmap)
3426 goto found;
3432 * Try check the SystemLink list first for a replacement font.
3433 * We may find good replacements there.
3435 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3437 if(!strcmpiW(font_link->font_name, FaceName) ||
3438 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3440 TRACE("found entry in system list\n");
3441 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3443 face = font_link_entry->face;
3444 family = face->family;
3445 if(csi.fs.fsCsb[0] &
3446 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3448 if(face->scalable || can_use_bitmap)
3449 goto found;
3456 psub = NULL; /* substitution is no more relevant */
3458 /* If requested charset was DEFAULT_CHARSET then try using charset
3459 corresponding to the current ansi codepage */
3460 if (!csi.fs.fsCsb[0])
3462 INT acp = GetACP();
3463 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3464 FIXME("TCI failed on codepage %d\n", acp);
3465 csi.fs.fsCsb[0] = 0;
3466 } else
3467 lf.lfCharSet = csi.ciCharset;
3470 /* Face families are in the top 4 bits of lfPitchAndFamily,
3471 so mask with 0xF0 before testing */
3473 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3474 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3475 strcpyW(lf.lfFaceName, defFixed);
3476 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3477 strcpyW(lf.lfFaceName, defSerif);
3478 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3479 strcpyW(lf.lfFaceName, defSans);
3480 else
3481 strcpyW(lf.lfFaceName, defSans);
3482 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3483 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3484 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3485 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3486 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3487 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3488 if(face->scalable || can_use_bitmap)
3489 goto found;
3494 last_resort_family = NULL;
3495 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3496 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3497 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3498 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3499 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3500 if(face->scalable)
3501 goto found;
3502 if(can_use_bitmap && !last_resort_family)
3503 last_resort_family = family;
3508 if(last_resort_family) {
3509 family = last_resort_family;
3510 csi.fs.fsCsb[0] = 0;
3511 goto found;
3514 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3515 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3516 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3517 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3518 if(face->scalable) {
3519 csi.fs.fsCsb[0] = 0;
3520 WARN("just using first face for now\n");
3521 goto found;
3523 if(can_use_bitmap && !last_resort_family)
3524 last_resort_family = family;
3527 if(!last_resort_family) {
3528 FIXME("can't find a single appropriate font - bailing\n");
3529 free_font(ret);
3530 LeaveCriticalSection( &freetype_cs );
3531 return NULL;
3534 WARN("could only find a bitmap font - this will probably look awful!\n");
3535 family = last_resort_family;
3536 csi.fs.fsCsb[0] = 0;
3538 found:
3539 it = lf.lfItalic ? 1 : 0;
3540 bd = lf.lfWeight > 550 ? 1 : 0;
3542 height = lf.lfHeight;
3544 face = best = best_bitmap = NULL;
3545 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3547 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3549 BOOL italic, bold;
3551 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3552 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3553 new_score = (italic ^ it) + (bold ^ bd);
3554 if(!best || new_score <= score)
3556 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3557 italic, bold, it, bd);
3558 score = new_score;
3559 best = face;
3560 if(best->scalable && score == 0) break;
3561 if(!best->scalable)
3563 if(height > 0)
3564 newdiff = height - (signed int)(best->size.height);
3565 else
3566 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3567 if(!best_bitmap || new_score < score ||
3568 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3570 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3571 diff = newdiff;
3572 best_bitmap = best;
3573 if(score == 0 && diff == 0) break;
3579 if(best)
3580 face = best->scalable ? best : best_bitmap;
3581 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3582 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3584 ret->fs = face->fs;
3586 if(csi.fs.fsCsb[0]) {
3587 ret->charset = lf.lfCharSet;
3588 ret->codepage = csi.ciACP;
3590 else
3591 ret->charset = get_nearest_charset(face, &ret->codepage);
3593 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3594 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3596 ret->aveWidth = height ? lf.lfWidth : 0;
3598 if(!face->scalable) {
3599 /* Windows uses integer scaling factors for bitmap fonts */
3600 INT scale, scaled_height;
3602 /* FIXME: rotation of bitmap fonts is ignored */
3603 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3604 if (ret->aveWidth)
3605 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3606 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3608 if (height != 0) height = diff;
3609 height += face->size.height;
3611 scale = (height + face->size.height - 1) / face->size.height;
3612 scaled_height = scale * face->size.height;
3613 /* XP allows not more than 10% deviation */
3614 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3615 ret->scale_y = scale;
3617 width = face->size.x_ppem >> 6;
3618 height = face->size.y_ppem >> 6;
3620 else
3621 ret->scale_y = 1.0;
3622 TRACE("font scale y: %f\n", ret->scale_y);
3624 ret->ft_face = OpenFontFace(ret, face, width, height);
3626 if (!ret->ft_face)
3628 free_font( ret );
3629 LeaveCriticalSection( &freetype_cs );
3630 return 0;
3633 ret->ntmFlags = face->ntmFlags;
3635 if (ret->charset == SYMBOL_CHARSET &&
3636 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3637 /* No ops */
3639 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3640 /* No ops */
3642 else {
3643 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3646 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3647 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3648 ret->underline = lf.lfUnderline ? 0xff : 0;
3649 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3650 create_child_font_list(ret);
3652 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3654 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3655 if (length != GDI_ERROR)
3657 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3658 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3659 TRACE("Loaded GSUB table of %i bytes\n",length);
3663 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3665 add_to_cache(ret);
3666 LeaveCriticalSection( &freetype_cs );
3667 return ret;
3670 static void dump_gdi_font_list(void)
3672 GdiFont *gdiFont;
3673 struct list *elem_ptr;
3675 TRACE("---------- gdiFont Cache ----------\n");
3676 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3677 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3678 TRACE("gdiFont=%p %s %d\n",
3679 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3682 TRACE("---------- Unused gdiFont Cache ----------\n");
3683 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3684 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3685 TRACE("gdiFont=%p %s %d\n",
3686 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3690 /*************************************************************
3691 * WineEngDestroyFontInstance
3693 * free the gdiFont associated with this handle
3696 BOOL WineEngDestroyFontInstance(HFONT handle)
3698 GdiFont *gdiFont;
3699 HFONTLIST *hflist;
3700 BOOL ret = FALSE;
3701 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3702 int i = 0;
3704 EnterCriticalSection( &freetype_cs );
3706 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3708 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3709 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3710 if(hflist->hfont == handle)
3712 TRACE("removing child font %p from child list\n", gdiFont);
3713 list_remove(&gdiFont->entry);
3714 LeaveCriticalSection( &freetype_cs );
3715 return TRUE;
3719 TRACE("destroying hfont=%p\n", handle);
3720 if(TRACE_ON(font))
3721 dump_gdi_font_list();
3723 font_elem_ptr = list_head(&gdi_font_list);
3724 while(font_elem_ptr) {
3725 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3726 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3728 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3729 while(hfontlist_elem_ptr) {
3730 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3731 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3732 if(hflist->hfont == handle) {
3733 list_remove(&hflist->entry);
3734 HeapFree(GetProcessHeap(), 0, hflist);
3735 ret = TRUE;
3738 if(list_empty(&gdiFont->hfontlist)) {
3739 TRACE("Moving to Unused list\n");
3740 list_remove(&gdiFont->entry);
3741 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3746 font_elem_ptr = list_head(&unused_gdi_font_list);
3747 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3748 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3749 while(font_elem_ptr) {
3750 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3751 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3752 TRACE("freeing %p\n", gdiFont);
3753 list_remove(&gdiFont->entry);
3754 free_font(gdiFont);
3756 LeaveCriticalSection( &freetype_cs );
3757 return ret;
3760 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3761 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3763 GdiFont *font;
3764 LONG width, height;
3766 if (face->cached_enum_data)
3768 TRACE("Cached\n");
3769 *pelf = face->cached_enum_data->elf;
3770 *pntm = face->cached_enum_data->ntm;
3771 *ptype = face->cached_enum_data->type;
3772 return;
3775 font = alloc_font();
3777 if(face->scalable) {
3778 height = -2048; /* 2048 is the most common em size */
3779 width = 0;
3780 } else {
3781 height = face->size.y_ppem >> 6;
3782 width = face->size.x_ppem >> 6;
3784 font->scale_y = 1.0;
3786 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3788 free_font(font);
3789 return;
3792 font->name = strdupW(face->family->FamilyName);
3793 font->ntmFlags = face->ntmFlags;
3795 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3797 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3799 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3801 lstrcpynW(pelf->elfLogFont.lfFaceName,
3802 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3803 LF_FACESIZE);
3804 lstrcpynW(pelf->elfFullName,
3805 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3806 LF_FULLFACESIZE);
3807 lstrcpynW(pelf->elfStyle,
3808 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3809 LF_FACESIZE);
3811 else
3813 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3815 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3817 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3818 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3819 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3822 pntm->ntmTm.ntmFlags = face->ntmFlags;
3823 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3824 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3825 pntm->ntmFontSig = face->fs;
3827 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3829 pelf->elfLogFont.lfEscapement = 0;
3830 pelf->elfLogFont.lfOrientation = 0;
3831 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3832 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3833 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3834 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3835 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3836 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3837 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3838 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3839 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3840 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3841 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3843 *ptype = 0;
3844 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3845 *ptype |= TRUETYPE_FONTTYPE;
3846 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3847 *ptype |= DEVICE_FONTTYPE;
3848 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3849 *ptype |= RASTER_FONTTYPE;
3851 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3852 if (face->cached_enum_data)
3854 face->cached_enum_data->elf = *pelf;
3855 face->cached_enum_data->ntm = *pntm;
3856 face->cached_enum_data->type = *ptype;
3859 free_font(font);
3862 /*************************************************************
3863 * WineEngEnumFonts
3866 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3868 Family *family;
3869 Face *face;
3870 struct list *family_elem_ptr, *face_elem_ptr;
3871 ENUMLOGFONTEXW elf;
3872 NEWTEXTMETRICEXW ntm;
3873 DWORD type;
3874 FONTSIGNATURE fs;
3875 CHARSETINFO csi;
3876 LOGFONTW lf;
3877 int i;
3879 if (!plf)
3881 lf.lfCharSet = DEFAULT_CHARSET;
3882 lf.lfPitchAndFamily = 0;
3883 lf.lfFaceName[0] = 0;
3884 plf = &lf;
3887 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3889 EnterCriticalSection( &freetype_cs );
3890 if(plf->lfFaceName[0]) {
3891 FontSubst *psub;
3892 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3894 if(psub) {
3895 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3896 debugstr_w(psub->to.name));
3897 lf = *plf;
3898 strcpyW(lf.lfFaceName, psub->to.name);
3899 plf = &lf;
3902 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3903 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3904 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3905 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3906 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3907 GetEnumStructs(face, &elf, &ntm, &type);
3908 for(i = 0; i < 32; i++) {
3909 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3910 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3911 strcpyW(elf.elfScript, OEM_DOSW);
3912 i = 32; /* break out of loop */
3913 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3914 continue;
3915 else {
3916 fs.fsCsb[0] = 1L << i;
3917 fs.fsCsb[1] = 0;
3918 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3919 TCI_SRCFONTSIG))
3920 csi.ciCharset = DEFAULT_CHARSET;
3921 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3922 if(csi.ciCharset != DEFAULT_CHARSET) {
3923 elf.elfLogFont.lfCharSet =
3924 ntm.ntmTm.tmCharSet = csi.ciCharset;
3925 if(ElfScriptsW[i])
3926 strcpyW(elf.elfScript, ElfScriptsW[i]);
3927 else
3928 FIXME("Unknown elfscript for bit %d\n", i);
3931 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3932 debugstr_w(elf.elfLogFont.lfFaceName),
3933 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3934 csi.ciCharset, type, debugstr_w(elf.elfScript),
3935 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3936 ntm.ntmTm.ntmFlags);
3937 /* release section before callback (FIXME) */
3938 LeaveCriticalSection( &freetype_cs );
3939 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3940 EnterCriticalSection( &freetype_cs );
3945 } else {
3946 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3947 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3948 face_elem_ptr = list_head(&family->faces);
3949 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3950 GetEnumStructs(face, &elf, &ntm, &type);
3951 for(i = 0; i < 32; i++) {
3952 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3953 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3954 strcpyW(elf.elfScript, OEM_DOSW);
3955 i = 32; /* break out of loop */
3956 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3957 continue;
3958 else {
3959 fs.fsCsb[0] = 1L << i;
3960 fs.fsCsb[1] = 0;
3961 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3962 TCI_SRCFONTSIG))
3963 csi.ciCharset = DEFAULT_CHARSET;
3964 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3965 if(csi.ciCharset != DEFAULT_CHARSET) {
3966 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3967 csi.ciCharset;
3968 if(ElfScriptsW[i])
3969 strcpyW(elf.elfScript, ElfScriptsW[i]);
3970 else
3971 FIXME("Unknown elfscript for bit %d\n", i);
3974 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3975 debugstr_w(elf.elfLogFont.lfFaceName),
3976 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3977 csi.ciCharset, type, debugstr_w(elf.elfScript),
3978 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3979 ntm.ntmTm.ntmFlags);
3980 /* release section before callback (FIXME) */
3981 LeaveCriticalSection( &freetype_cs );
3982 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3983 EnterCriticalSection( &freetype_cs );
3987 LeaveCriticalSection( &freetype_cs );
3988 return 1;
3991 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3993 pt->x.value = vec->x >> 6;
3994 pt->x.fract = (vec->x & 0x3f) << 10;
3995 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3996 pt->y.value = vec->y >> 6;
3997 pt->y.fract = (vec->y & 0x3f) << 10;
3998 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3999 return;
4002 /***************************************************
4003 * According to the MSDN documentation on WideCharToMultiByte,
4004 * certain codepages cannot set the default_used parameter.
4005 * This returns TRUE if the codepage can set that parameter, false else
4006 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4008 static BOOL codepage_sets_default_used(UINT codepage)
4010 switch (codepage)
4012 case CP_UTF7:
4013 case CP_UTF8:
4014 case CP_SYMBOL:
4015 return FALSE;
4016 default:
4017 return TRUE;
4022 * GSUB Table handling functions
4025 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4027 const GSUB_CoverageFormat1* cf1;
4029 cf1 = (GSUB_CoverageFormat1*)table;
4031 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4033 int count = GET_BE_WORD(cf1->GlyphCount);
4034 int i;
4035 TRACE("Coverage Format 1, %i glyphs\n",count);
4036 for (i = 0; i < count; i++)
4037 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4038 return i;
4039 return -1;
4041 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4043 const GSUB_CoverageFormat2* cf2;
4044 int i;
4045 int count;
4046 cf2 = (GSUB_CoverageFormat2*)cf1;
4048 count = GET_BE_WORD(cf2->RangeCount);
4049 TRACE("Coverage Format 2, %i ranges\n",count);
4050 for (i = 0; i < count; i++)
4052 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4053 return -1;
4054 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4055 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4057 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4058 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4061 return -1;
4063 else
4064 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4066 return -1;
4069 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4071 const GSUB_ScriptList *script;
4072 const GSUB_Script *deflt = NULL;
4073 int i;
4074 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4076 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4077 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4079 const GSUB_Script *scr;
4080 int offset;
4082 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4083 scr = (GSUB_Script*)((LPBYTE)script + offset);
4085 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4086 return scr;
4087 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4088 deflt = scr;
4090 return deflt;
4093 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4095 int i;
4096 int offset;
4097 const GSUB_LangSys *Lang;
4099 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4101 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4103 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4104 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4106 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4107 return Lang;
4109 offset = GET_BE_WORD(script->DefaultLangSys);
4110 if (offset)
4112 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4113 return Lang;
4115 return NULL;
4118 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4120 int i;
4121 const GSUB_FeatureList *feature;
4122 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4124 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4125 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4127 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4128 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4130 const GSUB_Feature *feat;
4131 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4132 return feat;
4135 return NULL;
4138 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4140 int i;
4141 int offset;
4142 const GSUB_LookupList *lookup;
4143 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4145 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4146 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4148 const GSUB_LookupTable *look;
4149 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4150 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4151 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4152 if (GET_BE_WORD(look->LookupType) != 1)
4153 FIXME("We only handle SubType 1\n");
4154 else
4156 int j;
4158 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4160 const GSUB_SingleSubstFormat1 *ssf1;
4161 offset = GET_BE_WORD(look->SubTable[j]);
4162 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4163 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4165 int offset = GET_BE_WORD(ssf1->Coverage);
4166 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4167 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4169 TRACE(" Glyph 0x%x ->",glyph);
4170 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4171 TRACE(" 0x%x\n",glyph);
4174 else
4176 const GSUB_SingleSubstFormat2 *ssf2;
4177 INT index;
4178 INT offset;
4180 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4181 offset = GET_BE_WORD(ssf1->Coverage);
4182 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4183 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4184 TRACE(" Coverage index %i\n",index);
4185 if (index != -1)
4187 TRACE(" Glyph is 0x%x ->",glyph);
4188 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4189 TRACE("0x%x\n",glyph);
4195 return glyph;
4198 static const char* get_opentype_script(const GdiFont *font)
4201 * I am not sure if this is the correct way to generate our script tag
4204 switch (font->charset)
4206 case ANSI_CHARSET: return "latn";
4207 case BALTIC_CHARSET: return "latn"; /* ?? */
4208 case CHINESEBIG5_CHARSET: return "hani";
4209 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4210 case GB2312_CHARSET: return "hani";
4211 case GREEK_CHARSET: return "grek";
4212 case HANGUL_CHARSET: return "hang";
4213 case RUSSIAN_CHARSET: return "cyrl";
4214 case SHIFTJIS_CHARSET: return "kana";
4215 case TURKISH_CHARSET: return "latn"; /* ?? */
4216 case VIETNAMESE_CHARSET: return "latn";
4217 case JOHAB_CHARSET: return "latn"; /* ?? */
4218 case ARABIC_CHARSET: return "arab";
4219 case HEBREW_CHARSET: return "hebr";
4220 case THAI_CHARSET: return "thai";
4221 default: return "latn";
4225 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4227 const GSUB_Header *header;
4228 const GSUB_Script *script;
4229 const GSUB_LangSys *language;
4230 const GSUB_Feature *feature;
4232 if (!font->GSUB_Table)
4233 return glyph;
4235 header = font->GSUB_Table;
4237 script = GSUB_get_script_table(header, get_opentype_script(font));
4238 if (!script)
4240 TRACE("Script not found\n");
4241 return glyph;
4243 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4244 if (!language)
4246 TRACE("Language not found\n");
4247 return glyph;
4249 feature = GSUB_get_feature(header, language, "vrt2");
4250 if (!feature)
4251 feature = GSUB_get_feature(header, language, "vert");
4252 if (!feature)
4254 TRACE("vrt2/vert feature not found\n");
4255 return glyph;
4257 return GSUB_apply_feature(header, feature, glyph);
4260 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4262 FT_UInt glyphId;
4264 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4265 WCHAR wc = (WCHAR)glyph;
4266 BOOL default_used;
4267 BOOL *default_used_pointer;
4268 FT_UInt ret;
4269 char buf;
4270 default_used_pointer = NULL;
4271 default_used = FALSE;
4272 if (codepage_sets_default_used(font->codepage))
4273 default_used_pointer = &default_used;
4274 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4275 ret = 0;
4276 else
4277 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4278 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4279 return get_GSUB_vert_glyph(font,ret);
4282 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4283 glyph = glyph + 0xf000;
4284 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4285 return get_GSUB_vert_glyph(font,glyphId);
4288 /*************************************************************
4289 * WineEngGetGlyphIndices
4292 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4293 LPWORD pgi, DWORD flags)
4295 int i;
4296 int default_char = -1;
4298 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4300 for(i = 0; i < count; i++)
4302 pgi[i] = get_glyph_index(font, lpstr[i]);
4303 if (pgi[i] == 0)
4305 if (default_char == -1)
4307 if (FT_IS_SFNT(font->ft_face))
4309 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4310 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4312 else
4314 TEXTMETRICW textm;
4315 WineEngGetTextMetrics(font, &textm);
4316 default_char = textm.tmDefaultChar;
4319 pgi[i] = default_char;
4322 return count;
4325 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4327 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4328 return !memcmp(matrix, &identity, sizeof(FMAT2));
4331 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4333 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4334 return !memcmp(matrix, &identity, sizeof(MAT2));
4337 /*************************************************************
4338 * WineEngGetGlyphOutline
4340 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4341 * except that the first parameter is the HWINEENGFONT of the font in
4342 * question rather than an HDC.
4345 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4346 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4347 const MAT2* lpmat)
4349 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4350 FT_Face ft_face = incoming_font->ft_face;
4351 GdiFont *font = incoming_font;
4352 FT_UInt glyph_index;
4353 DWORD width, height, pitch, needed = 0;
4354 FT_Bitmap ft_bitmap;
4355 FT_Error err;
4356 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4357 FT_Angle angle = 0;
4358 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4359 double widthRatio = 1.0;
4360 FT_Matrix transMat = identityMat;
4361 FT_Matrix transMatUnrotated;
4362 BOOL needsTransform = FALSE;
4363 BOOL tategaki = (font->GSUB_Table != NULL);
4364 UINT original_index;
4366 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4367 buflen, buf, lpmat);
4369 TRACE("font transform %f %f %f %f\n",
4370 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4371 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4373 EnterCriticalSection( &freetype_cs );
4375 if(format & GGO_GLYPH_INDEX) {
4376 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4377 original_index = glyph;
4378 format &= ~GGO_GLYPH_INDEX;
4379 } else {
4380 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4381 ft_face = font->ft_face;
4382 original_index = glyph_index;
4385 if(format & GGO_UNHINTED) {
4386 load_flags |= FT_LOAD_NO_HINTING;
4387 format &= ~GGO_UNHINTED;
4390 /* tategaki never appears to happen to lower glyph index */
4391 if (glyph_index < TATEGAKI_LOWER_BOUND )
4392 tategaki = FALSE;
4394 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4395 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4396 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4397 font->gmsize * sizeof(GM*));
4398 } else {
4399 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4400 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4402 *lpgm = FONT_GM(font,original_index)->gm;
4403 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4404 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4405 lpgm->gmCellIncX, lpgm->gmCellIncY);
4406 LeaveCriticalSection( &freetype_cs );
4407 return 1; /* FIXME */
4411 if (!font->gm[original_index / GM_BLOCK_SIZE])
4412 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4414 /* Scaling factor */
4415 if (font->aveWidth)
4417 TEXTMETRICW tm;
4419 WineEngGetTextMetrics(font, &tm);
4421 widthRatio = (double)font->aveWidth;
4422 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4424 else
4425 widthRatio = font->scale_y;
4427 /* Scaling transform */
4428 if (widthRatio != 1.0 || font->scale_y != 1.0)
4430 FT_Matrix scaleMat;
4431 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4432 scaleMat.xy = 0;
4433 scaleMat.yx = 0;
4434 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4436 pFT_Matrix_Multiply(&scaleMat, &transMat);
4437 needsTransform = TRUE;
4440 /* Slant transform */
4441 if (font->fake_italic) {
4442 FT_Matrix slantMat;
4444 slantMat.xx = (1 << 16);
4445 slantMat.xy = ((1 << 16) >> 2);
4446 slantMat.yx = 0;
4447 slantMat.yy = (1 << 16);
4448 pFT_Matrix_Multiply(&slantMat, &transMat);
4449 needsTransform = TRUE;
4452 /* Rotation transform */
4453 transMatUnrotated = transMat;
4454 if(font->orientation && !tategaki) {
4455 FT_Matrix rotationMat;
4456 FT_Vector vecAngle;
4457 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4458 pFT_Vector_Unit(&vecAngle, angle);
4459 rotationMat.xx = vecAngle.x;
4460 rotationMat.xy = -vecAngle.y;
4461 rotationMat.yx = -rotationMat.xy;
4462 rotationMat.yy = rotationMat.xx;
4464 pFT_Matrix_Multiply(&rotationMat, &transMat);
4465 needsTransform = TRUE;
4468 /* World transform */
4469 if (!is_identity_FMAT2(&font->font_desc.matrix))
4471 FT_Matrix worldMat;
4472 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4473 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4474 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4475 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4476 pFT_Matrix_Multiply(&worldMat, &transMat);
4477 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4478 needsTransform = TRUE;
4481 /* Extra transformation specified by caller */
4482 if (lpmat && !is_identity_MAT2(lpmat))
4484 FT_Matrix extraMat;
4485 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4486 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4487 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4488 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4489 pFT_Matrix_Multiply(&extraMat, &transMat);
4490 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4491 needsTransform = TRUE;
4494 if (needsTransform || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP))
4495 load_flags |= FT_LOAD_NO_BITMAP;
4497 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4499 if(err) {
4500 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4501 LeaveCriticalSection( &freetype_cs );
4502 return GDI_ERROR;
4505 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4506 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4508 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4509 lsb = left >> 6;
4510 bbx = (right - left) >> 6;
4512 if(!needsTransform) {
4513 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4514 bottom = (ft_face->glyph->metrics.horiBearingY -
4515 ft_face->glyph->metrics.height) & -64;
4516 lpgm->gmCellIncX = adv;
4517 lpgm->gmCellIncY = 0;
4518 } else {
4519 INT xc, yc;
4520 FT_Vector vec;
4521 for(xc = 0; xc < 2; xc++) {
4522 for(yc = 0; yc < 2; yc++) {
4523 vec.x = (ft_face->glyph->metrics.horiBearingX +
4524 xc * ft_face->glyph->metrics.width);
4525 vec.y = ft_face->glyph->metrics.horiBearingY -
4526 yc * ft_face->glyph->metrics.height;
4527 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4528 pFT_Vector_Transform(&vec, &transMat);
4529 if(xc == 0 && yc == 0) {
4530 left = right = vec.x;
4531 top = bottom = vec.y;
4532 } else {
4533 if(vec.x < left) left = vec.x;
4534 else if(vec.x > right) right = vec.x;
4535 if(vec.y < bottom) bottom = vec.y;
4536 else if(vec.y > top) top = vec.y;
4540 left = left & -64;
4541 right = (right + 63) & -64;
4542 bottom = bottom & -64;
4543 top = (top + 63) & -64;
4545 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4546 vec.x = ft_face->glyph->metrics.horiAdvance;
4547 vec.y = 0;
4548 pFT_Vector_Transform(&vec, &transMat);
4549 lpgm->gmCellIncX = (vec.x+63) >> 6;
4550 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4552 vec.x = ft_face->glyph->metrics.horiAdvance;
4553 vec.y = 0;
4554 pFT_Vector_Transform(&vec, &transMatUnrotated);
4555 adv = (vec.x+63) >> 6;
4557 lpgm->gmBlackBoxX = (right - left) >> 6;
4558 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4559 lpgm->gmptGlyphOrigin.x = left >> 6;
4560 lpgm->gmptGlyphOrigin.y = top >> 6;
4562 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4563 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4564 lpgm->gmCellIncX, lpgm->gmCellIncY);
4566 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4567 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4569 FONT_GM(font,original_index)->gm = *lpgm;
4570 FONT_GM(font,original_index)->adv = adv;
4571 FONT_GM(font,original_index)->lsb = lsb;
4572 FONT_GM(font,original_index)->bbx = bbx;
4573 FONT_GM(font,original_index)->init = TRUE;
4576 if(format == GGO_METRICS)
4578 LeaveCriticalSection( &freetype_cs );
4579 return 1; /* FIXME */
4582 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4583 TRACE("loaded a bitmap\n");
4584 LeaveCriticalSection( &freetype_cs );
4585 return GDI_ERROR;
4588 switch(format) {
4589 case GGO_BITMAP:
4590 width = lpgm->gmBlackBoxX;
4591 height = lpgm->gmBlackBoxY;
4592 pitch = ((width + 31) >> 5) << 2;
4593 needed = pitch * height;
4595 if(!buf || !buflen) break;
4597 switch(ft_face->glyph->format) {
4598 case ft_glyph_format_bitmap:
4600 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4601 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4602 INT h = ft_face->glyph->bitmap.rows;
4603 while(h--) {
4604 memcpy(dst, src, w);
4605 src += ft_face->glyph->bitmap.pitch;
4606 dst += pitch;
4608 break;
4611 case ft_glyph_format_outline:
4612 ft_bitmap.width = width;
4613 ft_bitmap.rows = height;
4614 ft_bitmap.pitch = pitch;
4615 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4616 ft_bitmap.buffer = buf;
4618 if(needsTransform)
4619 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4621 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4623 /* Note: FreeType will only set 'black' bits for us. */
4624 memset(buf, 0, needed);
4625 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4626 break;
4628 default:
4629 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4630 LeaveCriticalSection( &freetype_cs );
4631 return GDI_ERROR;
4633 break;
4635 case GGO_GRAY2_BITMAP:
4636 case GGO_GRAY4_BITMAP:
4637 case GGO_GRAY8_BITMAP:
4638 case WINE_GGO_GRAY16_BITMAP:
4640 unsigned int mult, row, col;
4641 BYTE *start, *ptr;
4643 width = lpgm->gmBlackBoxX;
4644 height = lpgm->gmBlackBoxY;
4645 pitch = (width + 3) / 4 * 4;
4646 needed = pitch * height;
4648 if(!buf || !buflen) break;
4650 switch(ft_face->glyph->format) {
4651 case ft_glyph_format_bitmap:
4653 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4654 INT h = ft_face->glyph->bitmap.rows;
4655 INT x;
4656 while(h--) {
4657 for(x = 0; x < pitch; x++)
4659 if(x < ft_face->glyph->bitmap.width)
4660 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4661 else
4662 dst[x] = 0;
4664 src += ft_face->glyph->bitmap.pitch;
4665 dst += pitch;
4667 LeaveCriticalSection( &freetype_cs );
4668 return needed;
4670 case ft_glyph_format_outline:
4672 ft_bitmap.width = width;
4673 ft_bitmap.rows = height;
4674 ft_bitmap.pitch = pitch;
4675 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4676 ft_bitmap.buffer = buf;
4678 if(needsTransform)
4679 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4681 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4683 memset(ft_bitmap.buffer, 0, buflen);
4685 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4687 if(format == GGO_GRAY2_BITMAP)
4688 mult = 4;
4689 else if(format == GGO_GRAY4_BITMAP)
4690 mult = 16;
4691 else if(format == GGO_GRAY8_BITMAP)
4692 mult = 64;
4693 else /* format == WINE_GGO_GRAY16_BITMAP */
4695 LeaveCriticalSection( &freetype_cs );
4696 return needed;
4698 break;
4700 default:
4701 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4702 LeaveCriticalSection( &freetype_cs );
4703 return GDI_ERROR;
4706 start = buf;
4707 for(row = 0; row < height; row++) {
4708 ptr = start;
4709 for(col = 0; col < width; col++, ptr++) {
4710 *ptr = (((int)*ptr) * mult + 128) / 256;
4712 start += pitch;
4714 break;
4717 case GGO_NATIVE:
4719 int contour, point = 0, first_pt;
4720 FT_Outline *outline = &ft_face->glyph->outline;
4721 TTPOLYGONHEADER *pph;
4722 TTPOLYCURVE *ppc;
4723 DWORD pph_start, cpfx, type;
4725 if(buflen == 0) buf = NULL;
4727 if (needsTransform && buf) {
4728 pFT_Outline_Transform(outline, &transMat);
4731 for(contour = 0; contour < outline->n_contours; contour++) {
4732 pph_start = needed;
4733 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4734 first_pt = point;
4735 if(buf) {
4736 pph->dwType = TT_POLYGON_TYPE;
4737 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4739 needed += sizeof(*pph);
4740 point++;
4741 while(point <= outline->contours[contour]) {
4742 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4743 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4744 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4745 cpfx = 0;
4746 do {
4747 if(buf)
4748 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4749 cpfx++;
4750 point++;
4751 } while(point <= outline->contours[contour] &&
4752 (outline->tags[point] & FT_Curve_Tag_On) ==
4753 (outline->tags[point-1] & FT_Curve_Tag_On));
4754 /* At the end of a contour Windows adds the start point, but
4755 only for Beziers */
4756 if(point > outline->contours[contour] &&
4757 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4758 if(buf)
4759 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4760 cpfx++;
4761 } else if(point <= outline->contours[contour] &&
4762 outline->tags[point] & FT_Curve_Tag_On) {
4763 /* add closing pt for bezier */
4764 if(buf)
4765 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4766 cpfx++;
4767 point++;
4769 if(buf) {
4770 ppc->wType = type;
4771 ppc->cpfx = cpfx;
4773 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4775 if(buf)
4776 pph->cb = needed - pph_start;
4778 break;
4780 case GGO_BEZIER:
4782 /* Convert the quadratic Beziers to cubic Beziers.
4783 The parametric eqn for a cubic Bezier is, from PLRM:
4784 r(t) = at^3 + bt^2 + ct + r0
4785 with the control points:
4786 r1 = r0 + c/3
4787 r2 = r1 + (c + b)/3
4788 r3 = r0 + c + b + a
4790 A quadratic Beizer has the form:
4791 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4793 So equating powers of t leads to:
4794 r1 = 2/3 p1 + 1/3 p0
4795 r2 = 2/3 p1 + 1/3 p2
4796 and of course r0 = p0, r3 = p2
4799 int contour, point = 0, first_pt;
4800 FT_Outline *outline = &ft_face->glyph->outline;
4801 TTPOLYGONHEADER *pph;
4802 TTPOLYCURVE *ppc;
4803 DWORD pph_start, cpfx, type;
4804 FT_Vector cubic_control[4];
4805 if(buflen == 0) buf = NULL;
4807 if (needsTransform && buf) {
4808 pFT_Outline_Transform(outline, &transMat);
4811 for(contour = 0; contour < outline->n_contours; contour++) {
4812 pph_start = needed;
4813 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4814 first_pt = point;
4815 if(buf) {
4816 pph->dwType = TT_POLYGON_TYPE;
4817 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4819 needed += sizeof(*pph);
4820 point++;
4821 while(point <= outline->contours[contour]) {
4822 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4823 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4824 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4825 cpfx = 0;
4826 do {
4827 if(type == TT_PRIM_LINE) {
4828 if(buf)
4829 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4830 cpfx++;
4831 point++;
4832 } else {
4833 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4834 so cpfx = 3n */
4836 /* FIXME: Possible optimization in endpoint calculation
4837 if there are two consecutive curves */
4838 cubic_control[0] = outline->points[point-1];
4839 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4840 cubic_control[0].x += outline->points[point].x + 1;
4841 cubic_control[0].y += outline->points[point].y + 1;
4842 cubic_control[0].x >>= 1;
4843 cubic_control[0].y >>= 1;
4845 if(point+1 > outline->contours[contour])
4846 cubic_control[3] = outline->points[first_pt];
4847 else {
4848 cubic_control[3] = outline->points[point+1];
4849 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4850 cubic_control[3].x += outline->points[point].x + 1;
4851 cubic_control[3].y += outline->points[point].y + 1;
4852 cubic_control[3].x >>= 1;
4853 cubic_control[3].y >>= 1;
4856 /* r1 = 1/3 p0 + 2/3 p1
4857 r2 = 1/3 p2 + 2/3 p1 */
4858 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4859 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4860 cubic_control[2] = cubic_control[1];
4861 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4862 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4863 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4864 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4865 if(buf) {
4866 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4867 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4868 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4870 cpfx += 3;
4871 point++;
4873 } while(point <= outline->contours[contour] &&
4874 (outline->tags[point] & FT_Curve_Tag_On) ==
4875 (outline->tags[point-1] & FT_Curve_Tag_On));
4876 /* At the end of a contour Windows adds the start point,
4877 but only for Beziers and we've already done that.
4879 if(point <= outline->contours[contour] &&
4880 outline->tags[point] & FT_Curve_Tag_On) {
4881 /* This is the closing pt of a bezier, but we've already
4882 added it, so just inc point and carry on */
4883 point++;
4885 if(buf) {
4886 ppc->wType = type;
4887 ppc->cpfx = cpfx;
4889 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4891 if(buf)
4892 pph->cb = needed - pph_start;
4894 break;
4897 default:
4898 FIXME("Unsupported format %d\n", format);
4899 LeaveCriticalSection( &freetype_cs );
4900 return GDI_ERROR;
4902 LeaveCriticalSection( &freetype_cs );
4903 return needed;
4906 static BOOL get_bitmap_text_metrics(GdiFont *font)
4908 FT_Face ft_face = font->ft_face;
4909 #ifdef HAVE_FREETYPE_FTWINFNT_H
4910 FT_WinFNT_HeaderRec winfnt_header;
4911 #endif
4912 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4913 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4914 font->potm->otmSize = size;
4916 #define TM font->potm->otmTextMetrics
4917 #ifdef HAVE_FREETYPE_FTWINFNT_H
4918 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4920 TM.tmHeight = winfnt_header.pixel_height;
4921 TM.tmAscent = winfnt_header.ascent;
4922 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4923 TM.tmInternalLeading = winfnt_header.internal_leading;
4924 TM.tmExternalLeading = winfnt_header.external_leading;
4925 TM.tmAveCharWidth = winfnt_header.avg_width;
4926 TM.tmMaxCharWidth = winfnt_header.max_width;
4927 TM.tmWeight = winfnt_header.weight;
4928 TM.tmOverhang = 0;
4929 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4930 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4931 TM.tmFirstChar = winfnt_header.first_char;
4932 TM.tmLastChar = winfnt_header.last_char;
4933 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4934 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4935 TM.tmItalic = winfnt_header.italic;
4936 TM.tmUnderlined = font->underline;
4937 TM.tmStruckOut = font->strikeout;
4938 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4939 TM.tmCharSet = winfnt_header.charset;
4941 else
4942 #endif
4944 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4945 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4946 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4947 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4948 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4949 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4950 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4951 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4952 TM.tmOverhang = 0;
4953 TM.tmDigitizedAspectX = 96; /* FIXME */
4954 TM.tmDigitizedAspectY = 96; /* FIXME */
4955 TM.tmFirstChar = 1;
4956 TM.tmLastChar = 255;
4957 TM.tmDefaultChar = 32;
4958 TM.tmBreakChar = 32;
4959 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4960 TM.tmUnderlined = font->underline;
4961 TM.tmStruckOut = font->strikeout;
4962 /* NB inverted meaning of TMPF_FIXED_PITCH */
4963 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4964 TM.tmCharSet = font->charset;
4966 #undef TM
4968 return TRUE;
4972 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4974 double scale_x, scale_y;
4976 if (font->aveWidth)
4978 scale_x = (double)font->aveWidth;
4979 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4981 else
4982 scale_x = font->scale_y;
4984 scale_x *= fabs(font->font_desc.matrix.eM11);
4985 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4987 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4988 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4990 SCALE_Y(ptm->tmHeight);
4991 SCALE_Y(ptm->tmAscent);
4992 SCALE_Y(ptm->tmDescent);
4993 SCALE_Y(ptm->tmInternalLeading);
4994 SCALE_Y(ptm->tmExternalLeading);
4995 SCALE_Y(ptm->tmOverhang);
4997 SCALE_X(ptm->tmAveCharWidth);
4998 SCALE_X(ptm->tmMaxCharWidth);
5000 #undef SCALE_X
5001 #undef SCALE_Y
5004 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5006 double scale_x, scale_y;
5008 if (font->aveWidth)
5010 scale_x = (double)font->aveWidth;
5011 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5013 else
5014 scale_x = font->scale_y;
5016 scale_x *= fabs(font->font_desc.matrix.eM11);
5017 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5019 scale_font_metrics(font, &potm->otmTextMetrics);
5021 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5022 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5024 SCALE_Y(potm->otmAscent);
5025 SCALE_Y(potm->otmDescent);
5026 SCALE_Y(potm->otmLineGap);
5027 SCALE_Y(potm->otmsCapEmHeight);
5028 SCALE_Y(potm->otmsXHeight);
5029 SCALE_Y(potm->otmrcFontBox.top);
5030 SCALE_Y(potm->otmrcFontBox.bottom);
5031 SCALE_X(potm->otmrcFontBox.left);
5032 SCALE_X(potm->otmrcFontBox.right);
5033 SCALE_Y(potm->otmMacAscent);
5034 SCALE_Y(potm->otmMacDescent);
5035 SCALE_Y(potm->otmMacLineGap);
5036 SCALE_X(potm->otmptSubscriptSize.x);
5037 SCALE_Y(potm->otmptSubscriptSize.y);
5038 SCALE_X(potm->otmptSubscriptOffset.x);
5039 SCALE_Y(potm->otmptSubscriptOffset.y);
5040 SCALE_X(potm->otmptSuperscriptSize.x);
5041 SCALE_Y(potm->otmptSuperscriptSize.y);
5042 SCALE_X(potm->otmptSuperscriptOffset.x);
5043 SCALE_Y(potm->otmptSuperscriptOffset.y);
5044 SCALE_Y(potm->otmsStrikeoutSize);
5045 SCALE_Y(potm->otmsStrikeoutPosition);
5046 SCALE_Y(potm->otmsUnderscoreSize);
5047 SCALE_Y(potm->otmsUnderscorePosition);
5049 #undef SCALE_X
5050 #undef SCALE_Y
5053 /*************************************************************
5054 * WineEngGetTextMetrics
5057 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5059 EnterCriticalSection( &freetype_cs );
5060 if(!font->potm) {
5061 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5062 if(!get_bitmap_text_metrics(font))
5064 LeaveCriticalSection( &freetype_cs );
5065 return FALSE;
5068 if(!font->potm)
5070 LeaveCriticalSection( &freetype_cs );
5071 return FALSE;
5073 *ptm = font->potm->otmTextMetrics;
5074 scale_font_metrics(font, ptm);
5075 LeaveCriticalSection( &freetype_cs );
5076 return TRUE;
5080 /*************************************************************
5081 * WineEngGetOutlineTextMetrics
5084 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5085 OUTLINETEXTMETRICW *potm)
5087 FT_Face ft_face = font->ft_face;
5088 UINT needed, lenfam, lensty, ret;
5089 TT_OS2 *pOS2;
5090 TT_HoriHeader *pHori;
5091 TT_Postscript *pPost;
5092 FT_Fixed x_scale, y_scale;
5093 WCHAR *family_nameW, *style_nameW;
5094 static const WCHAR spaceW[] = {' ', '\0'};
5095 char *cp;
5096 INT ascent, descent;
5098 TRACE("font=%p\n", font);
5100 if(!FT_IS_SCALABLE(ft_face))
5101 return 0;
5103 EnterCriticalSection( &freetype_cs );
5105 if(font->potm) {
5106 if(cbSize >= font->potm->otmSize)
5108 memcpy(potm, font->potm, font->potm->otmSize);
5109 scale_outline_font_metrics(font, potm);
5111 LeaveCriticalSection( &freetype_cs );
5112 return font->potm->otmSize;
5116 needed = sizeof(*potm);
5118 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5119 family_nameW = strdupW(font->name);
5121 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5122 * sizeof(WCHAR);
5123 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5124 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5125 style_nameW, lensty/sizeof(WCHAR));
5127 /* These names should be read from the TT name table */
5129 /* length of otmpFamilyName */
5130 needed += lenfam;
5132 /* length of otmpFaceName */
5133 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5134 needed += lenfam; /* just the family name */
5135 } else {
5136 needed += lenfam + lensty; /* family + " " + style */
5139 /* length of otmpStyleName */
5140 needed += lensty;
5142 /* length of otmpFullName */
5143 needed += lenfam + lensty;
5146 x_scale = ft_face->size->metrics.x_scale;
5147 y_scale = ft_face->size->metrics.y_scale;
5149 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5150 if(!pOS2) {
5151 FIXME("Can't find OS/2 table - not TT font?\n");
5152 ret = 0;
5153 goto end;
5156 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5157 if(!pHori) {
5158 FIXME("Can't find HHEA table - not TT font?\n");
5159 ret = 0;
5160 goto end;
5163 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5165 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",
5166 pOS2->usWinAscent, pOS2->usWinDescent,
5167 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5168 ft_face->ascender, ft_face->descender, ft_face->height,
5169 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5170 ft_face->bbox.yMax, ft_face->bbox.yMin);
5172 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5173 font->potm->otmSize = needed;
5175 #define TM font->potm->otmTextMetrics
5177 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5178 ascent = pHori->Ascender;
5179 descent = -pHori->Descender;
5180 } else {
5181 ascent = pOS2->usWinAscent;
5182 descent = pOS2->usWinDescent;
5185 if(font->yMax) {
5186 TM.tmAscent = font->yMax;
5187 TM.tmDescent = -font->yMin;
5188 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5189 } else {
5190 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5191 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5192 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5193 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5196 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5198 /* MSDN says:
5199 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5201 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5202 ((ascent + descent) -
5203 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5205 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5206 if (TM.tmAveCharWidth == 0) {
5207 TM.tmAveCharWidth = 1;
5209 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5210 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5211 TM.tmOverhang = 0;
5212 TM.tmDigitizedAspectX = 300;
5213 TM.tmDigitizedAspectY = 300;
5214 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5215 * symbol range to 0 - f0ff
5217 if (font->charset == SYMBOL_CHARSET)
5219 TM.tmFirstChar = 0;
5220 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5222 else
5224 TM.tmFirstChar = pOS2->usFirstCharIndex;
5225 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5227 TM.tmLastChar = pOS2->usLastCharIndex;
5228 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5229 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5230 TM.tmUnderlined = font->underline;
5231 TM.tmStruckOut = font->strikeout;
5233 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5234 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5235 (pOS2->version == 0xFFFFU ||
5236 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5237 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5238 else
5239 TM.tmPitchAndFamily = 0;
5241 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5242 case PAN_FAMILY_SCRIPT:
5243 TM.tmPitchAndFamily |= FF_SCRIPT;
5244 break;
5245 case PAN_FAMILY_DECORATIVE:
5246 case PAN_FAMILY_PICTORIAL:
5247 TM.tmPitchAndFamily |= FF_DECORATIVE;
5248 break;
5249 case PAN_FAMILY_TEXT_DISPLAY:
5250 if(TM.tmPitchAndFamily == 0) /* fixed */
5251 TM.tmPitchAndFamily = FF_MODERN;
5252 else {
5253 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5254 case PAN_SERIF_NORMAL_SANS:
5255 case PAN_SERIF_OBTUSE_SANS:
5256 case PAN_SERIF_PERP_SANS:
5257 TM.tmPitchAndFamily |= FF_SWISS;
5258 break;
5259 default:
5260 TM.tmPitchAndFamily |= FF_ROMAN;
5263 break;
5264 default:
5265 TM.tmPitchAndFamily |= FF_DONTCARE;
5268 if(FT_IS_SCALABLE(ft_face))
5269 TM.tmPitchAndFamily |= TMPF_VECTOR;
5271 if(FT_IS_SFNT(ft_face))
5273 if (font->ntmFlags & NTM_PS_OPENTYPE)
5274 TM.tmPitchAndFamily |= TMPF_DEVICE;
5275 else
5276 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5279 TM.tmCharSet = font->charset;
5281 font->potm->otmFiller = 0;
5282 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5283 font->potm->otmfsSelection = pOS2->fsSelection;
5284 font->potm->otmfsType = pOS2->fsType;
5285 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5286 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5287 font->potm->otmItalicAngle = 0; /* POST table */
5288 font->potm->otmEMSquare = ft_face->units_per_EM;
5289 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5290 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5291 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5292 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5293 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5294 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5295 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5296 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5297 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5298 font->potm->otmMacAscent = TM.tmAscent;
5299 font->potm->otmMacDescent = -TM.tmDescent;
5300 font->potm->otmMacLineGap = font->potm->otmLineGap;
5301 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5302 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5303 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5304 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5305 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5306 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5307 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5308 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5309 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5310 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5311 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5312 if(!pPost) {
5313 font->potm->otmsUnderscoreSize = 0;
5314 font->potm->otmsUnderscorePosition = 0;
5315 } else {
5316 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5317 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5319 #undef TM
5321 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5322 cp = (char*)font->potm + sizeof(*font->potm);
5323 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5324 strcpyW((WCHAR*)cp, family_nameW);
5325 cp += lenfam;
5326 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5327 strcpyW((WCHAR*)cp, style_nameW);
5328 cp += lensty;
5329 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5330 strcpyW((WCHAR*)cp, family_nameW);
5331 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5332 strcatW((WCHAR*)cp, spaceW);
5333 strcatW((WCHAR*)cp, style_nameW);
5334 cp += lenfam + lensty;
5335 } else
5336 cp += lenfam;
5337 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5338 strcpyW((WCHAR*)cp, family_nameW);
5339 strcatW((WCHAR*)cp, spaceW);
5340 strcatW((WCHAR*)cp, style_nameW);
5341 ret = needed;
5343 if(potm && needed <= cbSize)
5345 memcpy(potm, font->potm, font->potm->otmSize);
5346 scale_outline_font_metrics(font, potm);
5349 end:
5350 HeapFree(GetProcessHeap(), 0, style_nameW);
5351 HeapFree(GetProcessHeap(), 0, family_nameW);
5353 LeaveCriticalSection( &freetype_cs );
5354 return ret;
5357 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5359 HFONTLIST *hfontlist;
5360 child->font = alloc_font();
5361 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5362 if(!child->font->ft_face)
5364 free_font(child->font);
5365 child->font = NULL;
5366 return FALSE;
5369 child->font->font_desc = font->font_desc;
5370 child->font->ntmFlags = child->face->ntmFlags;
5371 child->font->orientation = font->orientation;
5372 child->font->scale_y = font->scale_y;
5373 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5374 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5375 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5376 child->font->base_font = font;
5377 list_add_head(&child_font_list, &child->font->entry);
5378 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5379 return TRUE;
5382 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5384 FT_UInt g;
5385 CHILD_FONT *child_font;
5387 if(font->base_font)
5388 font = font->base_font;
5390 *linked_font = font;
5392 if((*glyph = get_glyph_index(font, c)))
5393 return TRUE;
5395 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5397 if(!child_font->font)
5398 if(!load_child_font(font, child_font))
5399 continue;
5401 if(!child_font->font->ft_face)
5402 continue;
5403 g = get_glyph_index(child_font->font, c);
5404 if(g)
5406 *glyph = g;
5407 *linked_font = child_font->font;
5408 return TRUE;
5411 return FALSE;
5414 /*************************************************************
5415 * WineEngGetCharWidth
5418 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5419 LPINT buffer)
5421 UINT c;
5422 GLYPHMETRICS gm;
5423 FT_UInt glyph_index;
5424 GdiFont *linked_font;
5426 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5428 EnterCriticalSection( &freetype_cs );
5429 for(c = firstChar; c <= lastChar; c++) {
5430 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5431 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5432 &gm, 0, NULL, NULL);
5433 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5435 LeaveCriticalSection( &freetype_cs );
5436 return TRUE;
5439 /*************************************************************
5440 * WineEngGetCharABCWidths
5443 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5444 LPABC buffer)
5446 UINT c;
5447 GLYPHMETRICS gm;
5448 FT_UInt glyph_index;
5449 GdiFont *linked_font;
5451 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5453 if(!FT_IS_SCALABLE(font->ft_face))
5454 return FALSE;
5456 EnterCriticalSection( &freetype_cs );
5458 for(c = firstChar; c <= lastChar; c++) {
5459 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5460 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5461 &gm, 0, NULL, NULL);
5462 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5463 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5464 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5465 FONT_GM(linked_font,glyph_index)->bbx;
5467 LeaveCriticalSection( &freetype_cs );
5468 return TRUE;
5471 /*************************************************************
5472 * WineEngGetCharABCWidthsI
5475 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5476 LPABC buffer)
5478 UINT c;
5479 GLYPHMETRICS gm;
5480 FT_UInt glyph_index;
5481 GdiFont *linked_font;
5483 if(!FT_HAS_HORIZONTAL(font->ft_face))
5484 return FALSE;
5486 EnterCriticalSection( &freetype_cs );
5488 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5489 if (!pgi)
5490 for(c = firstChar; c < firstChar+count; c++) {
5491 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5492 &gm, 0, NULL, NULL);
5493 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5494 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5495 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5496 - FONT_GM(linked_font,c)->bbx;
5498 else
5499 for(c = 0; c < count; c++) {
5500 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5501 &gm, 0, NULL, NULL);
5502 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5503 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5504 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5505 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5508 LeaveCriticalSection( &freetype_cs );
5509 return TRUE;
5512 /*************************************************************
5513 * WineEngGetTextExtentExPoint
5516 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5517 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5519 INT idx;
5520 INT nfit = 0, ext;
5521 GLYPHMETRICS gm;
5522 TEXTMETRICW tm;
5523 FT_UInt glyph_index;
5524 GdiFont *linked_font;
5526 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5527 max_ext, size);
5529 EnterCriticalSection( &freetype_cs );
5531 size->cx = 0;
5532 WineEngGetTextMetrics(font, &tm);
5533 size->cy = tm.tmHeight;
5535 for(idx = 0; idx < count; idx++) {
5536 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5537 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5538 &gm, 0, NULL, NULL);
5539 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5540 ext = size->cx;
5541 if (! pnfit || ext <= max_ext) {
5542 ++nfit;
5543 if (dxs)
5544 dxs[idx] = ext;
5548 if (pnfit)
5549 *pnfit = nfit;
5551 LeaveCriticalSection( &freetype_cs );
5552 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5553 return TRUE;
5556 /*************************************************************
5557 * WineEngGetTextExtentExPointI
5560 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5561 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5563 INT idx;
5564 INT nfit = 0, ext;
5565 GLYPHMETRICS gm;
5566 TEXTMETRICW tm;
5568 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5570 EnterCriticalSection( &freetype_cs );
5572 size->cx = 0;
5573 WineEngGetTextMetrics(font, &tm);
5574 size->cy = tm.tmHeight;
5576 for(idx = 0; idx < count; idx++) {
5577 WineEngGetGlyphOutline(font, indices[idx],
5578 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5579 NULL);
5580 size->cx += FONT_GM(font,indices[idx])->adv;
5581 ext = size->cx;
5582 if (! pnfit || ext <= max_ext) {
5583 ++nfit;
5584 if (dxs)
5585 dxs[idx] = ext;
5589 if (pnfit)
5590 *pnfit = nfit;
5592 LeaveCriticalSection( &freetype_cs );
5593 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5594 return TRUE;
5597 /*************************************************************
5598 * WineEngGetFontData
5601 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5602 DWORD cbData)
5604 FT_Face ft_face = font->ft_face;
5605 FT_ULong len;
5606 FT_Error err;
5608 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5609 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5610 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5612 if(!FT_IS_SFNT(ft_face))
5613 return GDI_ERROR;
5615 if(!buf || !cbData)
5616 len = 0;
5617 else
5618 len = cbData;
5620 if(table) { /* MS tags differ in endianness from FT ones */
5621 table = table >> 24 | table << 24 |
5622 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5625 /* make sure value of len is the value freetype says it needs */
5626 if(buf && len)
5628 FT_ULong needed = 0;
5629 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5630 if( !err && needed < len) len = needed;
5632 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5634 if(err) {
5635 TRACE("Can't find table %c%c%c%c\n",
5636 /* bytes were reversed */
5637 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5638 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5639 return GDI_ERROR;
5641 return len;
5644 /*************************************************************
5645 * WineEngGetTextFace
5648 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5650 INT n = strlenW(font->name) + 1;
5651 if(str) {
5652 lstrcpynW(str, font->name, count);
5653 return min(count, n);
5654 } else
5655 return n;
5658 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5660 if (fs) *fs = font->fs;
5661 return font->charset;
5664 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5666 GdiFont *font = dc->gdiFont, *linked_font;
5667 struct list *first_hfont;
5668 BOOL ret;
5670 EnterCriticalSection( &freetype_cs );
5671 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5672 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5673 if(font == linked_font)
5674 *new_hfont = dc->hFont;
5675 else
5677 first_hfont = list_head(&linked_font->hfontlist);
5678 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5680 LeaveCriticalSection( &freetype_cs );
5681 return ret;
5684 /* Retrieve a list of supported Unicode ranges for a given font.
5685 * Can be called with NULL gs to calculate the buffer size. Returns
5686 * the number of ranges found.
5688 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5690 DWORD num_ranges = 0;
5692 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5694 FT_UInt glyph_code;
5695 FT_ULong char_code, char_code_prev;
5697 glyph_code = 0;
5698 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5700 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5701 face->num_glyphs, glyph_code, char_code);
5703 if (!glyph_code) return 0;
5705 if (gs)
5707 gs->ranges[0].wcLow = (USHORT)char_code;
5708 gs->ranges[0].cGlyphs = 0;
5709 gs->cGlyphsSupported = 0;
5712 num_ranges = 1;
5713 while (glyph_code)
5715 if (char_code < char_code_prev)
5717 ERR("expected increasing char code from FT_Get_Next_Char\n");
5718 return 0;
5720 if (char_code - char_code_prev > 1)
5722 num_ranges++;
5723 if (gs)
5725 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5726 gs->ranges[num_ranges - 1].cGlyphs = 1;
5727 gs->cGlyphsSupported++;
5730 else if (gs)
5732 gs->ranges[num_ranges - 1].cGlyphs++;
5733 gs->cGlyphsSupported++;
5735 char_code_prev = char_code;
5736 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5739 else
5740 FIXME("encoding %u not supported\n", face->charmap->encoding);
5742 return num_ranges;
5745 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5747 DWORD size = 0;
5748 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5750 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5751 if (glyphset)
5753 glyphset->cbThis = size;
5754 glyphset->cRanges = num_ranges;
5756 return size;
5759 /*************************************************************
5760 * FontIsLinked
5762 BOOL WineEngFontIsLinked(GdiFont *font)
5764 BOOL ret;
5765 EnterCriticalSection( &freetype_cs );
5766 ret = !list_empty(&font->child_fonts);
5767 LeaveCriticalSection( &freetype_cs );
5768 return ret;
5771 static BOOL is_hinting_enabled(void)
5773 /* Use the >= 2.2.0 function if available */
5774 if(pFT_Get_TrueType_Engine_Type)
5776 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5777 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5779 #ifdef FT_DRIVER_HAS_HINTER
5780 else
5782 FT_Module mod;
5784 /* otherwise if we've been compiled with < 2.2.0 headers
5785 use the internal macro */
5786 mod = pFT_Get_Module(library, "truetype");
5787 if(mod && FT_DRIVER_HAS_HINTER(mod))
5788 return TRUE;
5790 #endif
5792 return FALSE;
5795 /*************************************************************************
5796 * GetRasterizerCaps (GDI32.@)
5798 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5800 static int hinting = -1;
5802 if(hinting == -1)
5804 hinting = is_hinting_enabled();
5805 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5808 lprs->nSize = sizeof(RASTERIZER_STATUS);
5809 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5810 lprs->nLanguageID = 0;
5811 return TRUE;
5814 /*************************************************************
5815 * WineEngRealizationInfo
5817 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5819 FIXME("(%p, %p): stub!\n", font, info);
5821 info->flags = 1;
5822 if(FT_IS_SCALABLE(font->ft_face))
5823 info->flags |= 2;
5825 info->cache_num = font->cache_num;
5826 info->unknown2 = -1;
5827 return TRUE;
5830 /*************************************************************************
5831 * Kerning support for TrueType fonts
5833 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5835 struct TT_kern_table
5837 USHORT version;
5838 USHORT nTables;
5841 struct TT_kern_subtable
5843 USHORT version;
5844 USHORT length;
5845 union
5847 USHORT word;
5848 struct
5850 USHORT horizontal : 1;
5851 USHORT minimum : 1;
5852 USHORT cross_stream: 1;
5853 USHORT override : 1;
5854 USHORT reserved1 : 4;
5855 USHORT format : 8;
5856 } bits;
5857 } coverage;
5860 struct TT_format0_kern_subtable
5862 USHORT nPairs;
5863 USHORT searchRange;
5864 USHORT entrySelector;
5865 USHORT rangeShift;
5868 struct TT_kern_pair
5870 USHORT left;
5871 USHORT right;
5872 short value;
5875 static DWORD parse_format0_kern_subtable(GdiFont *font,
5876 const struct TT_format0_kern_subtable *tt_f0_ks,
5877 const USHORT *glyph_to_char,
5878 KERNINGPAIR *kern_pair, DWORD cPairs)
5880 USHORT i, nPairs;
5881 const struct TT_kern_pair *tt_kern_pair;
5883 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5885 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5887 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5888 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5889 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5891 if (!kern_pair || !cPairs)
5892 return nPairs;
5894 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5896 nPairs = min(nPairs, cPairs);
5898 for (i = 0; i < nPairs; i++)
5900 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5901 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5902 /* this algorithm appears to better match what Windows does */
5903 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5904 if (kern_pair->iKernAmount < 0)
5906 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5907 kern_pair->iKernAmount -= font->ppem;
5909 else if (kern_pair->iKernAmount > 0)
5911 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5912 kern_pair->iKernAmount += font->ppem;
5914 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5916 TRACE("left %u right %u value %d\n",
5917 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5919 kern_pair++;
5921 TRACE("copied %u entries\n", nPairs);
5922 return nPairs;
5925 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5927 DWORD length;
5928 void *buf;
5929 const struct TT_kern_table *tt_kern_table;
5930 const struct TT_kern_subtable *tt_kern_subtable;
5931 USHORT i, nTables;
5932 USHORT *glyph_to_char;
5934 EnterCriticalSection( &freetype_cs );
5935 if (font->total_kern_pairs != (DWORD)-1)
5937 if (cPairs && kern_pair)
5939 cPairs = min(cPairs, font->total_kern_pairs);
5940 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5941 LeaveCriticalSection( &freetype_cs );
5942 return cPairs;
5944 LeaveCriticalSection( &freetype_cs );
5945 return font->total_kern_pairs;
5948 font->total_kern_pairs = 0;
5950 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5952 if (length == GDI_ERROR)
5954 TRACE("no kerning data in the font\n");
5955 LeaveCriticalSection( &freetype_cs );
5956 return 0;
5959 buf = HeapAlloc(GetProcessHeap(), 0, length);
5960 if (!buf)
5962 WARN("Out of memory\n");
5963 LeaveCriticalSection( &freetype_cs );
5964 return 0;
5967 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5969 /* build a glyph index to char code map */
5970 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5971 if (!glyph_to_char)
5973 WARN("Out of memory allocating a glyph index to char code map\n");
5974 HeapFree(GetProcessHeap(), 0, buf);
5975 LeaveCriticalSection( &freetype_cs );
5976 return 0;
5979 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5981 FT_UInt glyph_code;
5982 FT_ULong char_code;
5984 glyph_code = 0;
5985 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5987 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5988 font->ft_face->num_glyphs, glyph_code, char_code);
5990 while (glyph_code)
5992 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5994 /* FIXME: This doesn't match what Windows does: it does some fancy
5995 * things with duplicate glyph index to char code mappings, while
5996 * we just avoid overriding existing entries.
5998 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5999 glyph_to_char[glyph_code] = (USHORT)char_code;
6001 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6004 else
6006 ULONG n;
6008 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6009 for (n = 0; n <= 65535; n++)
6010 glyph_to_char[n] = (USHORT)n;
6013 tt_kern_table = buf;
6014 nTables = GET_BE_WORD(tt_kern_table->nTables);
6015 TRACE("version %u, nTables %u\n",
6016 GET_BE_WORD(tt_kern_table->version), nTables);
6018 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6020 for (i = 0; i < nTables; i++)
6022 struct TT_kern_subtable tt_kern_subtable_copy;
6024 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6025 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6026 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6028 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6029 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6030 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6032 /* According to the TrueType specification this is the only format
6033 * that will be properly interpreted by Windows and OS/2
6035 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6037 DWORD new_chunk, old_total = font->total_kern_pairs;
6039 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6040 glyph_to_char, NULL, 0);
6041 font->total_kern_pairs += new_chunk;
6043 if (!font->kern_pairs)
6044 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6045 font->total_kern_pairs * sizeof(*font->kern_pairs));
6046 else
6047 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6048 font->total_kern_pairs * sizeof(*font->kern_pairs));
6050 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6051 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6053 else
6054 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6056 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6059 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6060 HeapFree(GetProcessHeap(), 0, buf);
6062 if (cPairs && kern_pair)
6064 cPairs = min(cPairs, font->total_kern_pairs);
6065 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6066 LeaveCriticalSection( &freetype_cs );
6067 return cPairs;
6069 LeaveCriticalSection( &freetype_cs );
6070 return font->total_kern_pairs;
6073 #else /* HAVE_FREETYPE */
6075 /*************************************************************************/
6077 BOOL WineEngInit(void)
6079 return FALSE;
6081 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6083 return NULL;
6085 BOOL WineEngDestroyFontInstance(HFONT hfont)
6087 return FALSE;
6090 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6092 return 1;
6095 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6096 LPWORD pgi, DWORD flags)
6098 return GDI_ERROR;
6101 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6102 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6103 const MAT2* lpmat)
6105 ERR("called but we don't have FreeType\n");
6106 return GDI_ERROR;
6109 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6111 ERR("called but we don't have FreeType\n");
6112 return FALSE;
6115 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6116 OUTLINETEXTMETRICW *potm)
6118 ERR("called but we don't have FreeType\n");
6119 return 0;
6122 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6123 LPINT buffer)
6125 ERR("called but we don't have FreeType\n");
6126 return FALSE;
6129 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6130 LPABC buffer)
6132 ERR("called but we don't have FreeType\n");
6133 return FALSE;
6136 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6137 LPABC buffer)
6139 ERR("called but we don't have FreeType\n");
6140 return FALSE;
6143 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6144 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6146 ERR("called but we don't have FreeType\n");
6147 return FALSE;
6150 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6151 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6153 ERR("called but we don't have FreeType\n");
6154 return FALSE;
6157 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6158 DWORD cbData)
6160 ERR("called but we don't have FreeType\n");
6161 return GDI_ERROR;
6164 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6166 ERR("called but we don't have FreeType\n");
6167 return 0;
6170 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6172 FIXME(":stub\n");
6173 return 1;
6176 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6178 FIXME(":stub\n");
6179 return TRUE;
6182 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6184 FIXME(":stub\n");
6185 return NULL;
6188 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6190 FIXME(":stub\n");
6191 return DEFAULT_CHARSET;
6194 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6196 return FALSE;
6199 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6201 FIXME("(%p, %p): stub\n", font, glyphset);
6202 return 0;
6205 BOOL WineEngFontIsLinked(GdiFont *font)
6207 return FALSE;
6210 /*************************************************************************
6211 * GetRasterizerCaps (GDI32.@)
6213 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6215 lprs->nSize = sizeof(RASTERIZER_STATUS);
6216 lprs->wFlags = 0;
6217 lprs->nLanguageID = 0;
6218 return TRUE;
6221 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6223 ERR("called but we don't have FreeType\n");
6224 return 0;
6227 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6229 ERR("called but we don't have FreeType\n");
6230 return FALSE;
6233 #endif /* HAVE_FREETYPE */