push a2e7360632735b5a2be8f61a9725e4e6969c5533
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob145be9be6333fe663e36ed89f5422167013ac75a
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 #ifdef FT_MULFIX_INLINED
167 #define pFT_MulFix FT_MULFIX_INLINED
168 #else
169 MAKE_FUNCPTR(FT_MulFix);
170 #endif
171 MAKE_FUNCPTR(FT_New_Face);
172 MAKE_FUNCPTR(FT_New_Memory_Face);
173 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
174 MAKE_FUNCPTR(FT_Outline_Transform);
175 MAKE_FUNCPTR(FT_Outline_Translate);
176 MAKE_FUNCPTR(FT_Select_Charmap);
177 MAKE_FUNCPTR(FT_Set_Charmap);
178 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
179 MAKE_FUNCPTR(FT_Vector_Transform);
180 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
181 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
182 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
183 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
184 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
185 #ifdef HAVE_FREETYPE_FTWINFNT_H
186 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
187 #endif
189 #ifdef SONAME_LIBFONTCONFIG
190 #include <fontconfig/fontconfig.h>
191 MAKE_FUNCPTR(FcConfigGetCurrent);
192 MAKE_FUNCPTR(FcFontList);
193 MAKE_FUNCPTR(FcFontSetDestroy);
194 MAKE_FUNCPTR(FcInit);
195 MAKE_FUNCPTR(FcObjectSetAdd);
196 MAKE_FUNCPTR(FcObjectSetCreate);
197 MAKE_FUNCPTR(FcObjectSetDestroy);
198 MAKE_FUNCPTR(FcPatternCreate);
199 MAKE_FUNCPTR(FcPatternDestroy);
200 MAKE_FUNCPTR(FcPatternGetBool);
201 MAKE_FUNCPTR(FcPatternGetString);
202 #endif
204 #undef MAKE_FUNCPTR
206 #ifndef FT_MAKE_TAG
207 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
208 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
209 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
210 #endif
212 #ifndef ft_encoding_none
213 #define FT_ENCODING_NONE ft_encoding_none
214 #endif
215 #ifndef ft_encoding_ms_symbol
216 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
217 #endif
218 #ifndef ft_encoding_unicode
219 #define FT_ENCODING_UNICODE ft_encoding_unicode
220 #endif
221 #ifndef ft_encoding_apple_roman
222 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
223 #endif
225 #ifdef WORDS_BIGENDIAN
226 #define GET_BE_WORD(x) (x)
227 #else
228 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
229 #endif
231 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
232 typedef struct {
233 FT_Short height;
234 FT_Short width;
235 FT_Pos size;
236 FT_Pos x_ppem;
237 FT_Pos y_ppem;
238 FT_Short internal_leading;
239 } Bitmap_Size;
241 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
242 So to let this compile on older versions of FreeType we'll define the
243 new structure here. */
244 typedef struct {
245 FT_Short height, width;
246 FT_Pos size, x_ppem, y_ppem;
247 } My_FT_Bitmap_Size;
249 struct enum_data
251 ENUMLOGFONTEXW elf;
252 NEWTEXTMETRICEXW ntm;
253 DWORD type;
256 typedef struct tagFace {
257 struct list entry;
258 WCHAR *StyleName;
259 char *file;
260 void *font_data_ptr;
261 DWORD font_data_size;
262 FT_Long face_index;
263 FONTSIGNATURE fs;
264 FONTSIGNATURE fs_links;
265 DWORD ntmFlags;
266 FT_Fixed font_version;
267 BOOL scalable;
268 Bitmap_Size size; /* set if face is a bitmap */
269 BOOL external; /* TRUE if we should manually add this font to the registry */
270 struct tagFamily *family;
271 /* Cached data for Enum */
272 struct enum_data *cached_enum_data;
273 } Face;
275 typedef struct tagFamily {
276 struct list entry;
277 const WCHAR *FamilyName;
278 struct list faces;
279 } Family;
281 typedef struct {
282 GLYPHMETRICS gm;
283 INT adv; /* These three hold to widths of the unrotated chars */
284 INT lsb;
285 INT bbx;
286 BOOL init;
287 } GM;
289 typedef struct {
290 FLOAT eM11, eM12;
291 FLOAT eM21, eM22;
292 } FMAT2;
294 typedef struct {
295 DWORD hash;
296 LOGFONTW lf;
297 FMAT2 matrix;
298 BOOL can_use_bitmap;
299 } FONT_DESC;
301 typedef struct tagHFONTLIST {
302 struct list entry;
303 HFONT hfont;
304 } HFONTLIST;
306 typedef struct {
307 struct list entry;
308 Face *face;
309 GdiFont *font;
310 } CHILD_FONT;
312 struct tagGdiFont {
313 struct list entry;
314 GM **gm;
315 DWORD gmsize;
316 struct list hfontlist;
317 OUTLINETEXTMETRICW *potm;
318 DWORD total_kern_pairs;
319 KERNINGPAIR *kern_pairs;
320 struct list child_fonts;
322 /* the following members can be accessed without locking, they are never modified after creation */
323 FT_Face ft_face;
324 struct font_mapping *mapping;
325 LPWSTR name;
326 int charset;
327 int codepage;
328 BOOL fake_italic;
329 BOOL fake_bold;
330 BYTE underline;
331 BYTE strikeout;
332 INT orientation;
333 FONT_DESC font_desc;
334 LONG aveWidth, ppem;
335 double scale_y;
336 SHORT yMax;
337 SHORT yMin;
338 DWORD ntmFlags;
339 FONTSIGNATURE fs;
340 GdiFont *base_font;
341 VOID *GSUB_Table;
342 DWORD cache_num;
345 typedef struct {
346 struct list entry;
347 const WCHAR *font_name;
348 struct list links;
349 } SYSTEM_LINKS;
351 #define GM_BLOCK_SIZE 128
352 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
354 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
355 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
356 #define UNUSED_CACHE_SIZE 10
357 static struct list child_font_list = LIST_INIT(child_font_list);
358 static struct list system_links = LIST_INIT(system_links);
360 static struct list font_subst_list = LIST_INIT(font_subst_list);
362 static struct list font_list = LIST_INIT(font_list);
364 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
365 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
366 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
368 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
369 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s',' ','N','T','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
380 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
381 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
382 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
384 static const WCHAR * const SystemFontValues[4] = {
385 System_Value,
386 OEMFont_Value,
387 FixedSys_Value,
388 NULL
391 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
392 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
394 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
395 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
396 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
397 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
398 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
399 'E','u','r','o','p','e','a','n','\0'};
400 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
401 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
402 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
403 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
404 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
405 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
406 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
407 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
408 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
409 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
410 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
411 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
413 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
414 WesternW, /*00*/
415 Central_EuropeanW,
416 CyrillicW,
417 GreekW,
418 TurkishW,
419 HebrewW,
420 ArabicW,
421 BalticW,
422 VietnameseW, /*08*/
423 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
424 ThaiW,
425 JapaneseW,
426 CHINESE_GB2312W,
427 HangulW,
428 CHINESE_BIG5W,
429 Hangul_Johab_W,
430 NULL, NULL, /*23*/
431 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
432 SymbolW /*31*/
435 typedef struct {
436 WCHAR *name;
437 INT charset;
438 } NameCs;
440 typedef struct tagFontSubst {
441 struct list entry;
442 NameCs from;
443 NameCs to;
444 } FontSubst;
446 struct font_mapping
448 struct list entry;
449 int refcount;
450 dev_t dev;
451 ino_t ino;
452 void *data;
453 size_t size;
456 static struct list mappings_list = LIST_INIT( mappings_list );
458 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
460 static CRITICAL_SECTION freetype_cs;
461 static CRITICAL_SECTION_DEBUG critsect_debug =
463 0, 0, &freetype_cs,
464 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
465 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
467 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
469 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
471 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
472 static BOOL use_default_fallback = FALSE;
474 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
476 /****************************************
477 * Notes on .fon files
479 * The fonts System, FixedSys and Terminal are special. There are typically multiple
480 * versions installed for different resolutions and codepages. Windows stores which one to use
481 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
482 * Key Meaning
483 * FIXEDFON.FON FixedSys
484 * FONTS.FON System
485 * OEMFONT.FON Terminal
486 * LogPixels Current dpi set by the display control panel applet
487 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
488 * also has a LogPixels value that appears to mirror this)
490 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
491 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
492 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
493 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
494 * so that makes sense.
496 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
497 * to be mapped into the registry on Windows 2000 at least).
498 * I have
499 * woafont=app850.fon
500 * ega80woa.fon=ega80850.fon
501 * ega40woa.fon=ega40850.fon
502 * cga80woa.fon=cga80850.fon
503 * cga40woa.fon=cga40850.fon
506 /* These are all structures needed for the GSUB table */
508 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
509 #define TATEGAKI_LOWER_BOUND 0x02F1
511 typedef struct {
512 DWORD version;
513 WORD ScriptList;
514 WORD FeatureList;
515 WORD LookupList;
516 } GSUB_Header;
518 typedef struct {
519 CHAR ScriptTag[4];
520 WORD Script;
521 } GSUB_ScriptRecord;
523 typedef struct {
524 WORD ScriptCount;
525 GSUB_ScriptRecord ScriptRecord[1];
526 } GSUB_ScriptList;
528 typedef struct {
529 CHAR LangSysTag[4];
530 WORD LangSys;
531 } GSUB_LangSysRecord;
533 typedef struct {
534 WORD DefaultLangSys;
535 WORD LangSysCount;
536 GSUB_LangSysRecord LangSysRecord[1];
537 } GSUB_Script;
539 typedef struct {
540 WORD LookupOrder; /* Reserved */
541 WORD ReqFeatureIndex;
542 WORD FeatureCount;
543 WORD FeatureIndex[1];
544 } GSUB_LangSys;
546 typedef struct {
547 CHAR FeatureTag[4];
548 WORD Feature;
549 } GSUB_FeatureRecord;
551 typedef struct {
552 WORD FeatureCount;
553 GSUB_FeatureRecord FeatureRecord[1];
554 } GSUB_FeatureList;
556 typedef struct {
557 WORD FeatureParams; /* Reserved */
558 WORD LookupCount;
559 WORD LookupListIndex[1];
560 } GSUB_Feature;
562 typedef struct {
563 WORD LookupCount;
564 WORD Lookup[1];
565 } GSUB_LookupList;
567 typedef struct {
568 WORD LookupType;
569 WORD LookupFlag;
570 WORD SubTableCount;
571 WORD SubTable[1];
572 } GSUB_LookupTable;
574 typedef struct {
575 WORD CoverageFormat;
576 WORD GlyphCount;
577 WORD GlyphArray[1];
578 } GSUB_CoverageFormat1;
580 typedef struct {
581 WORD Start;
582 WORD End;
583 WORD StartCoverageIndex;
584 } GSUB_RangeRecord;
586 typedef struct {
587 WORD CoverageFormat;
588 WORD RangeCount;
589 GSUB_RangeRecord RangeRecord[1];
590 } GSUB_CoverageFormat2;
592 typedef struct {
593 WORD SubstFormat; /* = 1 */
594 WORD Coverage;
595 WORD DeltaGlyphID;
596 } GSUB_SingleSubstFormat1;
598 typedef struct {
599 WORD SubstFormat; /* = 2 */
600 WORD Coverage;
601 WORD GlyphCount;
602 WORD Substitute[1];
603 }GSUB_SingleSubstFormat2;
605 #ifdef HAVE_CARBON_CARBON_H
606 static char *find_cache_dir(void)
608 FSRef ref;
609 OSErr err;
610 static char cached_path[MAX_PATH];
611 static const char *wine = "/Wine", *fonts = "/Fonts";
613 if(*cached_path) return cached_path;
615 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
616 if(err != noErr)
618 WARN("can't create cached data folder\n");
619 return NULL;
621 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
622 if(err != noErr)
624 WARN("can't create cached data path\n");
625 *cached_path = '\0';
626 return NULL;
628 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
630 ERR("Could not create full path\n");
631 *cached_path = '\0';
632 return NULL;
634 strcat(cached_path, wine);
636 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
638 WARN("Couldn't mkdir %s\n", cached_path);
639 *cached_path = '\0';
640 return NULL;
642 strcat(cached_path, fonts);
643 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
645 WARN("Couldn't mkdir %s\n", cached_path);
646 *cached_path = '\0';
647 return NULL;
649 return cached_path;
652 /******************************************************************
653 * expand_mac_font
655 * Extracts individual TrueType font files from a Mac suitcase font
656 * and saves them into the user's caches directory (see
657 * find_cache_dir()).
658 * Returns a NULL terminated array of filenames.
660 * We do this because they are apps that try to read ttf files
661 * themselves and they don't like Mac suitcase files.
663 static char **expand_mac_font(const char *path)
665 FSRef ref;
666 SInt16 res_ref;
667 OSStatus s;
668 unsigned int idx;
669 const char *out_dir;
670 const char *filename;
671 int output_len;
672 struct {
673 char **array;
674 unsigned int size, max_size;
675 } ret;
677 TRACE("path %s\n", path);
679 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
680 if(s != noErr)
682 WARN("failed to get ref\n");
683 return NULL;
686 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
687 if(s != noErr)
689 TRACE("no data fork, so trying resource fork\n");
690 res_ref = FSOpenResFile(&ref, fsRdPerm);
691 if(res_ref == -1)
693 TRACE("unable to open resource fork\n");
694 return NULL;
698 ret.size = 0;
699 ret.max_size = 10;
700 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
701 if(!ret.array)
703 CloseResFile(res_ref);
704 return NULL;
707 out_dir = find_cache_dir();
709 filename = strrchr(path, '/');
710 if(!filename) filename = path;
711 else filename++;
713 /* output filename has the form out_dir/filename_%04x.ttf */
714 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
716 UseResFile(res_ref);
717 idx = 1;
718 while(1)
720 FamRec *fam_rec;
721 unsigned short *num_faces_ptr, num_faces, face;
722 AsscEntry *assoc;
723 Handle fond;
724 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
726 fond = Get1IndResource(fond_res, idx);
727 if(!fond) break;
728 TRACE("got fond resource %d\n", idx);
729 HLock(fond);
731 fam_rec = *(FamRec**)fond;
732 num_faces_ptr = (unsigned short *)(fam_rec + 1);
733 num_faces = GET_BE_WORD(*num_faces_ptr);
734 num_faces++;
735 assoc = (AsscEntry*)(num_faces_ptr + 1);
736 TRACE("num faces %04x\n", num_faces);
737 for(face = 0; face < num_faces; face++, assoc++)
739 Handle sfnt;
740 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
741 unsigned short size, font_id;
742 char *output;
744 size = GET_BE_WORD(assoc->fontSize);
745 font_id = GET_BE_WORD(assoc->fontID);
746 if(size != 0)
748 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
749 continue;
752 TRACE("trying to load sfnt id %04x\n", font_id);
753 sfnt = GetResource(sfnt_res, font_id);
754 if(!sfnt)
756 TRACE("can't get sfnt resource %04x\n", font_id);
757 continue;
760 output = HeapAlloc(GetProcessHeap(), 0, output_len);
761 if(output)
763 int fd;
765 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
767 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
768 if(fd != -1 || errno == EEXIST)
770 if(fd != -1)
772 unsigned char *sfnt_data;
774 HLock(sfnt);
775 sfnt_data = *(unsigned char**)sfnt;
776 write(fd, sfnt_data, GetHandleSize(sfnt));
777 HUnlock(sfnt);
778 close(fd);
780 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
782 ret.max_size *= 2;
783 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
785 ret.array[ret.size++] = output;
787 else
789 WARN("unable to create %s\n", output);
790 HeapFree(GetProcessHeap(), 0, output);
793 ReleaseResource(sfnt);
795 HUnlock(fond);
796 ReleaseResource(fond);
797 idx++;
799 CloseResFile(res_ref);
801 return ret.array;
804 #endif /* HAVE_CARBON_CARBON_H */
806 static inline BOOL is_win9x(void)
808 return GetVersion() & 0x80000000;
811 This function builds an FT_Fixed from a double. It fails if the absolute
812 value of the float number is greater than 32768.
814 static inline FT_Fixed FT_FixedFromFloat(double f)
816 return f * 0x10000;
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
825 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
829 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
831 Family *family;
832 Face *face;
833 const char *file;
834 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
835 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
837 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
840 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
842 if(face_name && strcmpiW(face_name, family->FamilyName))
843 continue;
844 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
846 if (!face->file)
847 continue;
848 file = strrchr(face->file, '/');
849 if(!file)
850 file = face->file;
851 else
852 file++;
853 if(!strcasecmp(file, file_nameA))
855 HeapFree(GetProcessHeap(), 0, file_nameA);
856 return face;
860 HeapFree(GetProcessHeap(), 0, file_nameA);
861 return NULL;
864 static Family *find_family_from_name(const WCHAR *name)
866 Family *family;
868 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
870 if(!strcmpiW(family->FamilyName, name))
871 return family;
874 return NULL;
877 static void DumpSubstList(void)
879 FontSubst *psub;
881 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
883 if(psub->from.charset != -1 || psub->to.charset != -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
885 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
886 else
887 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
888 debugstr_w(psub->to.name));
890 return;
893 static LPWSTR strdupW(LPCWSTR p)
895 LPWSTR ret;
896 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
897 ret = HeapAlloc(GetProcessHeap(), 0, len);
898 memcpy(ret, p, len);
899 return ret;
902 static LPSTR strdupA(LPCSTR p)
904 LPSTR ret;
905 DWORD len = (strlen(p) + 1);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
907 memcpy(ret, p, len);
908 return ret;
911 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
912 INT from_charset)
914 FontSubst *element;
916 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
918 if(!strcmpiW(element->from.name, from_name) &&
919 (element->from.charset == from_charset ||
920 element->from.charset == -1))
921 return element;
924 return NULL;
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
931 FontSubst *from_exist, *to_exist;
933 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
935 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
937 list_remove(&from_exist->entry);
938 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
939 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
940 HeapFree(GetProcessHeap(), 0, from_exist);
941 from_exist = NULL;
944 if(!from_exist)
946 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
948 if(to_exist)
950 HeapFree(GetProcessHeap(), 0, subst->to.name);
951 subst->to.name = strdupW(to_exist->to.name);
954 list_add_tail(subst_list, &subst->entry);
956 return TRUE;
959 HeapFree(GetProcessHeap(), 0, subst->from.name);
960 HeapFree(GetProcessHeap(), 0, subst->to.name);
961 HeapFree(GetProcessHeap(), 0, subst);
962 return FALSE;
965 static void split_subst_info(NameCs *nc, LPSTR str)
967 CHAR *p = strrchr(str, ',');
968 DWORD len;
970 nc->charset = -1;
971 if(p && *(p+1)) {
972 nc->charset = strtol(p+1, NULL, 10);
973 *p = '\0';
975 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
976 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
980 static void LoadSubstList(void)
982 FontSubst *psub;
983 HKEY hkey;
984 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
985 LPSTR value;
986 LPVOID data;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey) == ERROR_SUCCESS) {
992 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 &valuelen, &datalen, NULL, NULL);
995 valuelen++; /* returned value doesn't include room for '\0' */
996 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
997 data = HeapAlloc(GetProcessHeap(), 0, datalen);
999 dlen = datalen;
1000 vlen = valuelen;
1001 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1002 &dlen) == ERROR_SUCCESS) {
1003 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1005 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1006 split_subst_info(&psub->from, value);
1007 split_subst_info(&psub->to, data);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1012 psub->to.charset == DEFAULT_CHARSET) {
1013 HeapFree(GetProcessHeap(), 0, psub->to.name);
1014 HeapFree(GetProcessHeap(), 0, psub->from.name);
1015 HeapFree(GetProcessHeap(), 0, psub);
1016 } else {
1017 add_font_subst(&font_subst_list, psub, 0);
1019 /* reset dlen and vlen */
1020 dlen = datalen;
1021 vlen = valuelen;
1023 HeapFree(GetProcessHeap(), 0, data);
1024 HeapFree(GetProcessHeap(), 0, value);
1025 RegCloseKey(hkey);
1030 /*****************************************************************
1031 * get_name_table_entry
1033 * Supply the platform, encoding, language and name ids in req
1034 * and if the name exists the function will fill in the string
1035 * and string_len members. The string is owned by FreeType so
1036 * don't free it. Returns TRUE if the name is found else FALSE.
1038 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1040 FT_SfntName name;
1041 FT_UInt num_names, name_index;
1043 if(FT_IS_SFNT(ft_face))
1045 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1047 for(name_index = 0; name_index < num_names; name_index++)
1049 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1051 if((name.platform_id == req->platform_id) &&
1052 (name.encoding_id == req->encoding_id) &&
1053 (name.language_id == req->language_id) &&
1054 (name.name_id == req->name_id))
1056 req->string = name.string;
1057 req->string_len = name.string_len;
1058 return TRUE;
1063 req->string = NULL;
1064 req->string_len = 0;
1065 return FALSE;
1068 static WCHAR *get_familyname(FT_Face ft_face)
1070 WCHAR *family = NULL;
1071 FT_SfntName name;
1073 name.platform_id = TT_PLATFORM_MICROSOFT;
1074 name.encoding_id = TT_MS_ID_UNICODE_CS;
1075 name.language_id = GetUserDefaultLCID();
1076 name.name_id = TT_NAME_ID_FONT_FAMILY;
1078 if(get_name_table_entry(ft_face, &name))
1080 int i;
1082 /* String is not nul terminated and string_len is a byte length. */
1083 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1084 for(i = 0; i < name.string_len / 2; i++)
1086 WORD *tmp = (WORD *)&name.string[i * 2];
1087 family[i] = GET_BE_WORD(*tmp);
1089 family[i] = 0;
1090 TRACE("Got localised name %s\n", debugstr_w(family));
1093 return family;
1097 /*****************************************************************
1098 * load_sfnt_table
1100 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1101 * of FreeType that don't export this function.
1104 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1107 FT_Error err;
1109 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1110 if(pFT_Load_Sfnt_Table)
1112 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1114 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1115 else /* Do it the hard way */
1117 TT_Face tt_face = (TT_Face) ft_face;
1118 SFNT_Interface *sfnt;
1119 if (FT_Version.major==2 && FT_Version.minor==0)
1121 /* 2.0.x */
1122 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1124 else
1126 /* A field was added in the middle of the structure in 2.1.x */
1127 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1129 err = sfnt->load_any(tt_face, table, offset, buf, len);
1131 #else
1132 else
1134 static int msg;
1135 if(!msg)
1137 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1138 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1139 "Please upgrade your freetype library.\n");
1140 msg++;
1142 err = FT_Err_Unimplemented_Feature;
1144 #endif
1145 return err;
1148 static inline int TestStyles(DWORD flags, DWORD styles)
1150 return (flags & styles) == styles;
1153 static int StyleOrdering(Face *face)
1155 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1156 return 3;
1157 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1158 return 2;
1159 if (TestStyles(face->ntmFlags, NTM_BOLD))
1160 return 1;
1161 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1162 return 0;
1164 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1165 debugstr_w(face->family->FamilyName),
1166 debugstr_w(face->StyleName),
1167 face->ntmFlags);
1169 return 9999;
1172 /* Add a style of face to a font family using an ordering of the list such
1173 that regular fonts come before bold and italic, and single styles come
1174 before compound styles. */
1175 static void AddFaceToFamily(Face *face, Family *family)
1177 struct list *entry;
1179 LIST_FOR_EACH( entry, &family->faces )
1181 Face *ent = LIST_ENTRY(entry, Face, entry);
1182 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1184 list_add_before( entry, &face->entry );
1187 #define ADDFONT_EXTERNAL_FONT 0x01
1188 #define ADDFONT_FORCE_BITMAP 0x02
1189 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1191 FT_Face ft_face;
1192 TT_OS2 *pOS2;
1193 TT_Header *pHeader = NULL;
1194 WCHAR *english_family, *localised_family, *StyleW;
1195 DWORD len;
1196 Family *family;
1197 Face *face;
1198 struct list *family_elem_ptr, *face_elem_ptr;
1199 FT_Error err;
1200 FT_Long face_index = 0, num_faces;
1201 #ifdef HAVE_FREETYPE_FTWINFNT_H
1202 FT_WinFNT_HeaderRec winfnt_header;
1203 #endif
1204 int i, bitmap_num, internal_leading;
1205 FONTSIGNATURE fs;
1207 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1208 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1210 #ifdef HAVE_CARBON_CARBON_H
1211 if(file && !fake_family)
1213 char **mac_list = expand_mac_font(file);
1214 if(mac_list)
1216 BOOL had_one = FALSE;
1217 char **cursor;
1218 for(cursor = mac_list; *cursor; cursor++)
1220 had_one = TRUE;
1221 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1222 HeapFree(GetProcessHeap(), 0, *cursor);
1224 HeapFree(GetProcessHeap(), 0, mac_list);
1225 if(had_one)
1226 return 1;
1229 #endif /* HAVE_CARBON_CARBON_H */
1231 do {
1232 char *family_name = fake_family;
1234 if (file)
1236 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1237 err = pFT_New_Face(library, file, face_index, &ft_face);
1238 } else
1240 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1241 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1244 if(err != 0) {
1245 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1246 return 0;
1249 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*/
1250 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1251 pFT_Done_Face(ft_face);
1252 return 0;
1255 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1256 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1257 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1258 pFT_Done_Face(ft_face);
1259 return 0;
1262 if(FT_IS_SFNT(ft_face))
1264 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1265 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1266 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1268 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1269 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1270 pFT_Done_Face(ft_face);
1271 return 0;
1274 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1275 we don't want to load these. */
1276 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1278 FT_ULong len = 0;
1280 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1282 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1283 pFT_Done_Face(ft_face);
1284 return 0;
1289 if(!ft_face->family_name || !ft_face->style_name) {
1290 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1291 pFT_Done_Face(ft_face);
1292 return 0;
1295 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1297 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1298 pFT_Done_Face(ft_face);
1299 return 0;
1302 if (target_family)
1304 localised_family = get_familyname(ft_face);
1305 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1307 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1308 HeapFree(GetProcessHeap(), 0, localised_family);
1309 num_faces = ft_face->num_faces;
1310 pFT_Done_Face(ft_face);
1311 continue;
1313 HeapFree(GetProcessHeap(), 0, localised_family);
1316 if(!family_name)
1317 family_name = ft_face->family_name;
1319 bitmap_num = 0;
1320 do {
1321 My_FT_Bitmap_Size *size = NULL;
1322 FT_ULong tmp_size;
1324 if(!FT_IS_SCALABLE(ft_face))
1325 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1327 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1328 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1329 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1331 localised_family = NULL;
1332 if(!fake_family) {
1333 localised_family = get_familyname(ft_face);
1334 if(localised_family && !strcmpW(localised_family, english_family)) {
1335 HeapFree(GetProcessHeap(), 0, localised_family);
1336 localised_family = NULL;
1340 family = NULL;
1341 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1342 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1343 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1344 break;
1345 family = NULL;
1347 if(!family) {
1348 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1349 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1350 list_init(&family->faces);
1351 list_add_tail(&font_list, &family->entry);
1353 if(localised_family) {
1354 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1355 subst->from.name = strdupW(english_family);
1356 subst->from.charset = -1;
1357 subst->to.name = strdupW(localised_family);
1358 subst->to.charset = -1;
1359 add_font_subst(&font_subst_list, subst, 0);
1362 HeapFree(GetProcessHeap(), 0, localised_family);
1363 HeapFree(GetProcessHeap(), 0, english_family);
1365 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1366 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1367 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1369 internal_leading = 0;
1370 memset(&fs, 0, sizeof(fs));
1372 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1373 if(pOS2) {
1374 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1375 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1376 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1377 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1378 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1379 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1380 if(pOS2->version == 0) {
1381 FT_UInt dummy;
1383 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1384 fs.fsCsb[0] |= FS_LATIN1;
1385 else
1386 fs.fsCsb[0] |= FS_SYMBOL;
1389 #ifdef HAVE_FREETYPE_FTWINFNT_H
1390 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1391 CHARSETINFO csi;
1392 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1393 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1394 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1395 fs = csi.fs;
1396 internal_leading = winfnt_header.internal_leading;
1398 #endif
1400 face_elem_ptr = list_head(&family->faces);
1401 while(face_elem_ptr) {
1402 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1403 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1404 if(!strcmpW(face->StyleName, StyleW) &&
1405 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1406 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1407 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1408 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1410 if(fake_family) {
1411 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1412 HeapFree(GetProcessHeap(), 0, StyleW);
1413 pFT_Done_Face(ft_face);
1414 return 1;
1416 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1417 TRACE("Original font is newer so skipping this one\n");
1418 HeapFree(GetProcessHeap(), 0, StyleW);
1419 pFT_Done_Face(ft_face);
1420 return 1;
1421 } else {
1422 TRACE("Replacing original with this one\n");
1423 list_remove(&face->entry);
1424 HeapFree(GetProcessHeap(), 0, face->file);
1425 HeapFree(GetProcessHeap(), 0, face->StyleName);
1426 HeapFree(GetProcessHeap(), 0, face);
1427 break;
1431 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1432 face->cached_enum_data = NULL;
1433 face->StyleName = StyleW;
1434 if (file)
1436 face->file = strdupA(file);
1437 face->font_data_ptr = NULL;
1438 face->font_data_size = 0;
1440 else
1442 face->file = NULL;
1443 face->font_data_ptr = font_data_ptr;
1444 face->font_data_size = font_data_size;
1446 face->face_index = face_index;
1447 face->ntmFlags = 0;
1448 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1449 face->ntmFlags |= NTM_ITALIC;
1450 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1451 face->ntmFlags |= NTM_BOLD;
1452 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1453 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1454 face->family = family;
1455 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1456 face->fs = fs;
1457 memset(&face->fs_links, 0, sizeof(face->fs_links));
1459 if(FT_IS_SCALABLE(ft_face)) {
1460 memset(&face->size, 0, sizeof(face->size));
1461 face->scalable = TRUE;
1462 } else {
1463 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1464 size->height, size->width, size->size >> 6,
1465 size->x_ppem >> 6, size->y_ppem >> 6);
1466 face->size.height = size->height;
1467 face->size.width = size->width;
1468 face->size.size = size->size;
1469 face->size.x_ppem = size->x_ppem;
1470 face->size.y_ppem = size->y_ppem;
1471 face->size.internal_leading = internal_leading;
1472 face->scalable = FALSE;
1475 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1476 tmp_size = 0;
1477 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1479 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1480 face->ntmFlags |= NTM_PS_OPENTYPE;
1483 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1484 face->fs.fsCsb[0], face->fs.fsCsb[1],
1485 face->fs.fsUsb[0], face->fs.fsUsb[1],
1486 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1489 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1490 for(i = 0; i < ft_face->num_charmaps; i++) {
1491 switch(ft_face->charmaps[i]->encoding) {
1492 case FT_ENCODING_UNICODE:
1493 case FT_ENCODING_APPLE_ROMAN:
1494 face->fs.fsCsb[0] |= FS_LATIN1;
1495 break;
1496 case FT_ENCODING_MS_SYMBOL:
1497 face->fs.fsCsb[0] |= FS_SYMBOL;
1498 break;
1499 default:
1500 break;
1505 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1506 have_installed_roman_font = TRUE;
1508 AddFaceToFamily(face, family);
1510 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1512 num_faces = ft_face->num_faces;
1513 pFT_Done_Face(ft_face);
1514 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1515 debugstr_w(StyleW));
1516 } while(num_faces > ++face_index);
1517 return num_faces;
1520 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1522 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1525 static void DumpFontList(void)
1527 Family *family;
1528 Face *face;
1529 struct list *family_elem_ptr, *face_elem_ptr;
1531 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1532 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1533 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1534 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1535 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1536 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1537 if(!face->scalable)
1538 TRACE(" %d", face->size.height);
1539 TRACE("\n");
1542 return;
1545 /***********************************************************
1546 * The replacement list is a way to map an entire font
1547 * family onto another family. For example adding
1549 * [HKCU\Software\Wine\Fonts\Replacements]
1550 * "Wingdings"="Winedings"
1552 * would enumerate the Winedings font both as Winedings and
1553 * Wingdings. However if a real Wingdings font is present the
1554 * replacement does not take place.
1557 static void LoadReplaceList(void)
1559 HKEY hkey;
1560 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1561 LPWSTR value;
1562 LPVOID data;
1563 Family *family;
1564 Face *face;
1565 struct list *family_elem_ptr, *face_elem_ptr;
1566 CHAR familyA[400];
1568 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1569 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1571 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1572 &valuelen, &datalen, NULL, NULL);
1574 valuelen++; /* returned value doesn't include room for '\0' */
1575 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1576 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1578 dlen = datalen;
1579 vlen = valuelen;
1580 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1581 &dlen) == ERROR_SUCCESS) {
1582 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1583 /* "NewName"="Oldname" */
1584 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1586 /* Find the old family and hence all of the font files
1587 in that family */
1588 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1589 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1590 if(!strcmpiW(family->FamilyName, data)) {
1591 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1592 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1593 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1594 debugstr_w(face->StyleName), familyA);
1595 /* Now add a new entry with the new family name */
1596 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1598 break;
1601 /* reset dlen and vlen */
1602 dlen = datalen;
1603 vlen = valuelen;
1605 HeapFree(GetProcessHeap(), 0, data);
1606 HeapFree(GetProcessHeap(), 0, value);
1607 RegCloseKey(hkey);
1611 /*************************************************************
1612 * init_system_links
1614 static BOOL init_system_links(void)
1616 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1617 'W','i','n','d','o','w','s',' ','N','T','\\',
1618 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1619 'S','y','s','t','e','m','L','i','n','k',0};
1620 HKEY hkey;
1621 BOOL ret = FALSE;
1622 DWORD type, max_val, max_data, val_len, data_len, index;
1623 WCHAR *value, *data;
1624 WCHAR *entry, *next;
1625 SYSTEM_LINKS *font_link, *system_font_link;
1626 CHILD_FONT *child_font;
1627 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1628 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1629 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1630 FONTSIGNATURE fs;
1631 Family *family;
1632 Face *face;
1633 FontSubst *psub;
1635 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1637 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1638 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1639 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1640 val_len = max_val + 1;
1641 data_len = max_data;
1642 index = 0;
1643 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1645 TRACE("%s:\n", debugstr_w(value));
1647 memset(&fs, 0, sizeof(fs));
1648 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1649 psub = get_font_subst(&font_subst_list, value, -1);
1650 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1651 list_init(&font_link->links);
1652 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1654 WCHAR *face_name;
1655 CHILD_FONT *child_font;
1657 TRACE("\t%s\n", debugstr_w(entry));
1659 next = entry + strlenW(entry) + 1;
1661 face_name = strchrW(entry, ',');
1662 if(face_name)
1664 *face_name++ = 0;
1665 while(isspaceW(*face_name))
1666 face_name++;
1668 psub = get_font_subst(&font_subst_list, face_name, -1);
1669 if(psub)
1670 face_name = psub->to.name;
1672 face = find_face_from_filename(entry, face_name);
1673 if(!face)
1675 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1676 continue;
1679 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1680 child_font->face = face;
1681 child_font->font = NULL;
1682 fs.fsCsb[0] |= face->fs.fsCsb[0];
1683 fs.fsCsb[1] |= face->fs.fsCsb[1];
1684 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1685 list_add_tail(&font_link->links, &child_font->entry);
1687 family = find_family_from_name(font_link->font_name);
1688 if(family)
1690 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1692 face->fs_links = fs;
1695 list_add_tail(&system_links, &font_link->entry);
1696 val_len = max_val + 1;
1697 data_len = max_data;
1700 HeapFree(GetProcessHeap(), 0, value);
1701 HeapFree(GetProcessHeap(), 0, data);
1702 RegCloseKey(hkey);
1705 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1706 that Tahoma has */
1708 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1709 system_font_link->font_name = strdupW(System);
1710 list_init(&system_font_link->links);
1712 face = find_face_from_filename(tahoma_ttf, Tahoma);
1713 if(face)
1715 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1716 child_font->face = face;
1717 child_font->font = NULL;
1718 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1719 list_add_tail(&system_font_link->links, &child_font->entry);
1721 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1723 if(!strcmpiW(font_link->font_name, Tahoma))
1725 CHILD_FONT *font_link_entry;
1726 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1728 CHILD_FONT *new_child;
1729 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1730 new_child->face = font_link_entry->face;
1731 new_child->font = NULL;
1732 list_add_tail(&system_font_link->links, &new_child->entry);
1734 break;
1737 list_add_tail(&system_links, &system_font_link->entry);
1738 return ret;
1741 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1743 DIR *dir;
1744 struct dirent *dent;
1745 char path[MAX_PATH];
1747 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1749 dir = opendir(dirname);
1750 if(!dir) {
1751 WARN("Can't open directory %s\n", debugstr_a(dirname));
1752 return FALSE;
1754 while((dent = readdir(dir)) != NULL) {
1755 struct stat statbuf;
1757 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1758 continue;
1760 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1762 sprintf(path, "%s/%s", dirname, dent->d_name);
1764 if(stat(path, &statbuf) == -1)
1766 WARN("Can't stat %s\n", debugstr_a(path));
1767 continue;
1769 if(S_ISDIR(statbuf.st_mode))
1770 ReadFontDir(path, external_fonts);
1771 else
1772 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1774 closedir(dir);
1775 return TRUE;
1778 static void load_fontconfig_fonts(void)
1780 #ifdef SONAME_LIBFONTCONFIG
1781 void *fc_handle = NULL;
1782 FcConfig *config;
1783 FcPattern *pat;
1784 FcObjectSet *os;
1785 FcFontSet *fontset;
1786 int i, len;
1787 char *file;
1788 const char *ext;
1790 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1791 if(!fc_handle) {
1792 TRACE("Wine cannot find the fontconfig library (%s).\n",
1793 SONAME_LIBFONTCONFIG);
1794 return;
1796 #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;}
1797 LOAD_FUNCPTR(FcConfigGetCurrent);
1798 LOAD_FUNCPTR(FcFontList);
1799 LOAD_FUNCPTR(FcFontSetDestroy);
1800 LOAD_FUNCPTR(FcInit);
1801 LOAD_FUNCPTR(FcObjectSetAdd);
1802 LOAD_FUNCPTR(FcObjectSetCreate);
1803 LOAD_FUNCPTR(FcObjectSetDestroy);
1804 LOAD_FUNCPTR(FcPatternCreate);
1805 LOAD_FUNCPTR(FcPatternDestroy);
1806 LOAD_FUNCPTR(FcPatternGetBool);
1807 LOAD_FUNCPTR(FcPatternGetString);
1808 #undef LOAD_FUNCPTR
1810 if(!pFcInit()) return;
1812 config = pFcConfigGetCurrent();
1813 pat = pFcPatternCreate();
1814 os = pFcObjectSetCreate();
1815 pFcObjectSetAdd(os, FC_FILE);
1816 pFcObjectSetAdd(os, FC_SCALABLE);
1817 fontset = pFcFontList(config, pat, os);
1818 if(!fontset) return;
1819 for(i = 0; i < fontset->nfont; i++) {
1820 FcBool scalable;
1822 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1823 continue;
1824 TRACE("fontconfig: %s\n", file);
1826 /* We're just interested in OT/TT fonts for now, so this hack just
1827 picks up the scalable fonts without extensions .pf[ab] to save time
1828 loading every other font */
1830 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1832 TRACE("not scalable\n");
1833 continue;
1836 len = strlen( file );
1837 if(len < 4) continue;
1838 ext = &file[ len - 3 ];
1839 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1840 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1842 pFcFontSetDestroy(fontset);
1843 pFcObjectSetDestroy(os);
1844 pFcPatternDestroy(pat);
1845 sym_not_found:
1846 #endif
1847 return;
1850 static BOOL load_font_from_data_dir(LPCWSTR file)
1852 BOOL ret = FALSE;
1853 const char *data_dir = wine_get_data_dir();
1855 if (!data_dir) data_dir = wine_get_build_dir();
1857 if (data_dir)
1859 INT len;
1860 char *unix_name;
1862 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1864 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1866 strcpy(unix_name, data_dir);
1867 strcat(unix_name, "/fonts/");
1869 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1871 EnterCriticalSection( &freetype_cs );
1872 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1873 LeaveCriticalSection( &freetype_cs );
1874 HeapFree(GetProcessHeap(), 0, unix_name);
1876 return ret;
1879 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1881 static const WCHAR slashW[] = {'\\','\0'};
1882 BOOL ret = FALSE;
1883 WCHAR windowsdir[MAX_PATH];
1884 char *unixname;
1886 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1887 strcatW(windowsdir, fontsW);
1888 strcatW(windowsdir, slashW);
1889 strcatW(windowsdir, file);
1890 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1891 EnterCriticalSection( &freetype_cs );
1892 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1893 LeaveCriticalSection( &freetype_cs );
1894 HeapFree(GetProcessHeap(), 0, unixname);
1896 return ret;
1899 static void load_system_fonts(void)
1901 HKEY hkey;
1902 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1903 const WCHAR * const *value;
1904 DWORD dlen, type;
1905 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1906 char *unixname;
1908 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1909 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1910 strcatW(windowsdir, fontsW);
1911 for(value = SystemFontValues; *value; value++) {
1912 dlen = sizeof(data);
1913 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1914 type == REG_SZ) {
1915 BOOL added = FALSE;
1917 sprintfW(pathW, fmtW, windowsdir, data);
1918 if((unixname = wine_get_unix_file_name(pathW))) {
1919 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1920 HeapFree(GetProcessHeap(), 0, unixname);
1922 if (!added)
1923 load_font_from_data_dir(data);
1926 RegCloseKey(hkey);
1930 /*************************************************************
1932 * This adds registry entries for any externally loaded fonts
1933 * (fonts from fontconfig or FontDirs). It also deletes entries
1934 * of no longer existing fonts.
1937 static void update_reg_entries(void)
1939 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1940 LPWSTR valueW;
1941 DWORD len, len_fam;
1942 Family *family;
1943 Face *face;
1944 struct list *family_elem_ptr, *face_elem_ptr;
1945 WCHAR *file;
1946 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1947 static const WCHAR spaceW[] = {' ', '\0'};
1948 char *path;
1950 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1951 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1952 ERR("Can't create Windows font reg key\n");
1953 goto end;
1956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1957 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1958 ERR("Can't create Windows font reg key\n");
1959 goto end;
1962 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1963 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1964 ERR("Can't create external font reg key\n");
1965 goto end;
1968 /* enumerate the fonts and add external ones to the two keys */
1970 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1971 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1972 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1973 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1974 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1975 if(!face->external) continue;
1976 len = len_fam;
1977 if (!(face->ntmFlags & NTM_REGULAR))
1978 len = len_fam + strlenW(face->StyleName) + 1;
1979 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1980 strcpyW(valueW, family->FamilyName);
1981 if(len != len_fam) {
1982 strcatW(valueW, spaceW);
1983 strcatW(valueW, face->StyleName);
1985 strcatW(valueW, TrueType);
1987 file = wine_get_dos_file_name(face->file);
1988 if(file)
1989 len = strlenW(file) + 1;
1990 else
1992 if((path = strrchr(face->file, '/')) == NULL)
1993 path = face->file;
1994 else
1995 path++;
1996 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1998 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1999 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2001 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2002 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2003 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2005 HeapFree(GetProcessHeap(), 0, file);
2006 HeapFree(GetProcessHeap(), 0, valueW);
2009 end:
2010 if(external_key) RegCloseKey(external_key);
2011 if(win9x_key) RegCloseKey(win9x_key);
2012 if(winnt_key) RegCloseKey(winnt_key);
2013 return;
2016 static void delete_external_font_keys(void)
2018 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2019 DWORD dlen, vlen, datalen, valuelen, i, type;
2020 LPWSTR valueW;
2021 LPVOID data;
2023 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2024 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2025 ERR("Can't create Windows font reg key\n");
2026 goto end;
2029 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2030 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2031 ERR("Can't create Windows font reg key\n");
2032 goto end;
2035 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2036 ERR("Can't create external font reg key\n");
2037 goto end;
2040 /* Delete all external fonts added last time */
2042 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2043 &valuelen, &datalen, NULL, NULL);
2044 valuelen++; /* returned value doesn't include room for '\0' */
2045 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2046 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2048 dlen = datalen * sizeof(WCHAR);
2049 vlen = valuelen;
2050 i = 0;
2051 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2052 &dlen) == ERROR_SUCCESS) {
2054 RegDeleteValueW(winnt_key, valueW);
2055 RegDeleteValueW(win9x_key, valueW);
2056 /* reset dlen and vlen */
2057 dlen = datalen;
2058 vlen = valuelen;
2060 HeapFree(GetProcessHeap(), 0, data);
2061 HeapFree(GetProcessHeap(), 0, valueW);
2063 /* Delete the old external fonts key */
2064 RegCloseKey(external_key);
2065 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2067 end:
2068 if(win9x_key) RegCloseKey(win9x_key);
2069 if(winnt_key) RegCloseKey(winnt_key);
2072 /*************************************************************
2073 * WineEngAddFontResourceEx
2076 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2078 INT ret = 0;
2079 if (ft_handle) /* do it only if we have freetype up and running */
2081 char *unixname;
2083 if(flags)
2084 FIXME("Ignoring flags %x\n", flags);
2086 if((unixname = wine_get_unix_file_name(file)))
2088 EnterCriticalSection( &freetype_cs );
2089 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2090 LeaveCriticalSection( &freetype_cs );
2091 HeapFree(GetProcessHeap(), 0, unixname);
2093 if (!ret && !strchrW(file, '\\')) {
2094 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2095 ret = load_font_from_winfonts_dir(file);
2096 if (!ret) {
2097 /* Try in datadir/fonts (or builddir/fonts),
2098 * needed for Magic the Gathering Online
2100 ret = load_font_from_data_dir(file);
2104 return ret;
2107 /*************************************************************
2108 * WineEngAddFontMemResourceEx
2111 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2113 if (ft_handle) /* do it only if we have freetype up and running */
2115 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2117 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2118 memcpy(pFontCopy, pbFont, cbFont);
2120 EnterCriticalSection( &freetype_cs );
2121 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2122 LeaveCriticalSection( &freetype_cs );
2124 if (*pcFonts == 0)
2126 TRACE("AddFontToList failed\n");
2127 HeapFree(GetProcessHeap(), 0, pFontCopy);
2128 return NULL;
2130 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2131 * For now return something unique but quite random
2133 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2134 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2137 *pcFonts = 0;
2138 return 0;
2141 /*************************************************************
2142 * WineEngRemoveFontResourceEx
2145 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2147 FIXME(":stub\n");
2148 return TRUE;
2151 static const struct nls_update_font_list
2153 UINT ansi_cp, oem_cp;
2154 const char *oem, *fixed, *system;
2155 const char *courier, *serif, *small, *sserif;
2156 /* these are for font substitutes */
2157 const char *shelldlg, *tmsrmn;
2158 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2159 *helv_0, *tmsrmn_0;
2160 const struct subst
2162 const char *from, *to;
2163 } arial_0, courier_new_0, times_new_roman_0;
2164 } nls_update_font_list[] =
2166 /* Latin 1 (United States) */
2167 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2168 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2169 "Tahoma","Times New Roman",
2170 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2171 { 0 }, { 0 }, { 0 }
2173 /* Latin 1 (Multilingual) */
2174 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2175 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2176 "Tahoma","Times New Roman", /* FIXME unverified */
2177 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2178 { 0 }, { 0 }, { 0 }
2180 /* Eastern Europe */
2181 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2182 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2183 "Tahoma","Times New Roman", /* FIXME unverified */
2184 "Fixedsys,238", "System,238",
2185 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2186 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2187 { "Arial CE,0", "Arial,238" },
2188 { "Courier New CE,0", "Courier New,238" },
2189 { "Times New Roman CE,0", "Times New Roman,238" }
2191 /* Cyrillic */
2192 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2193 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2194 "Tahoma","Times New Roman", /* FIXME unverified */
2195 "Fixedsys,204", "System,204",
2196 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2197 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2198 { "Arial Cyr,0", "Arial,204" },
2199 { "Courier New Cyr,0", "Courier New,204" },
2200 { "Times New Roman Cyr,0", "Times New Roman,204" }
2202 /* Greek */
2203 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2204 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,161", "System,161",
2207 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2208 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2209 { "Arial Greek,0", "Arial,161" },
2210 { "Courier New Greek,0", "Courier New,161" },
2211 { "Times New Roman Greek,0", "Times New Roman,161" }
2213 /* Turkish */
2214 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2215 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,162", "System,162",
2218 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2219 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2220 { "Arial Tur,0", "Arial,162" },
2221 { "Courier New Tur,0", "Courier New,162" },
2222 { "Times New Roman Tur,0", "Times New Roman,162" }
2224 /* Hebrew */
2225 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2226 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,177", "System,177",
2229 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2230 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2231 { 0 }, { 0 }, { 0 }
2233 /* Arabic */
2234 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2235 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2236 "Tahoma","Times New Roman", /* FIXME unverified */
2237 "Fixedsys,178", "System,178",
2238 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2239 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2240 { 0 }, { 0 }, { 0 }
2242 /* Baltic */
2243 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2244 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,186", "System,186",
2247 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2248 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2249 { "Arial Baltic,0", "Arial,186" },
2250 { "Courier New Baltic,0", "Courier New,186" },
2251 { "Times New Roman Baltic,0", "Times New Roman,186" }
2253 /* Vietnamese */
2254 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2255 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2258 { 0 }, { 0 }, { 0 }
2260 /* Thai */
2261 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2262 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2265 { 0 }, { 0 }, { 0 }
2267 /* Japanese */
2268 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2269 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2270 "MS UI Gothic","MS Serif",
2271 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2272 { 0 }, { 0 }, { 0 }
2274 /* Chinese Simplified */
2275 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2276 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2277 "Tahoma", "Times New Roman", /* FIXME unverified */
2278 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2279 { 0 }, { 0 }, { 0 }
2281 /* Korean */
2282 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2283 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2284 "Gulim", "Batang",
2285 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2286 { 0 }, { 0 }, { 0 }
2288 /* Chinese Traditional */
2289 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2291 "PMingLiU", "MingLiU",
2292 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2293 { 0 }, { 0 }, { 0 }
2297 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2299 return ( ansi_cp == 932 /* CP932 for Japanese */
2300 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2301 || ansi_cp == 949 /* CP949 for Korean */
2302 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2305 static inline HKEY create_fonts_NT_registry_key(void)
2307 HKEY hkey = 0;
2309 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2310 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2311 return hkey;
2314 static inline HKEY create_fonts_9x_registry_key(void)
2316 HKEY hkey = 0;
2318 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2319 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2320 return hkey;
2323 static inline HKEY create_config_fonts_registry_key(void)
2325 HKEY hkey = 0;
2327 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2328 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2329 return hkey;
2332 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2334 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2335 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2336 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2337 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2340 static void set_value_key(HKEY hkey, const char *name, const char *value)
2342 if (value)
2343 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2344 else if (name)
2345 RegDeleteValueA(hkey, name);
2348 static void update_font_info(void)
2350 char buf[40], cpbuf[40];
2351 DWORD len, type;
2352 HKEY hkey = 0;
2353 UINT i, ansi_cp = 0, oem_cp = 0;
2354 BOOL done = FALSE;
2356 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2357 return;
2359 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2360 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2361 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2362 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2363 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2365 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2366 if (is_dbcs_ansi_cp(ansi_cp))
2367 use_default_fallback = TRUE;
2369 len = sizeof(buf);
2370 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2372 if (!strcmp( buf, cpbuf )) /* already set correctly */
2374 RegCloseKey(hkey);
2375 return;
2377 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2379 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2381 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2382 RegCloseKey(hkey);
2384 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2386 HKEY hkey;
2388 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2389 nls_update_font_list[i].oem_cp == oem_cp)
2391 hkey = create_config_fonts_registry_key();
2392 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2393 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2394 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2395 RegCloseKey(hkey);
2397 hkey = create_fonts_NT_registry_key();
2398 add_font_list(hkey, &nls_update_font_list[i]);
2399 RegCloseKey(hkey);
2401 hkey = create_fonts_9x_registry_key();
2402 add_font_list(hkey, &nls_update_font_list[i]);
2403 RegCloseKey(hkey);
2405 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2407 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2408 strlen(nls_update_font_list[i].shelldlg)+1);
2409 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2410 strlen(nls_update_font_list[i].tmsrmn)+1);
2412 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2413 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2414 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2415 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2416 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2417 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2418 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2419 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2421 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2422 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2423 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2425 RegCloseKey(hkey);
2427 done = TRUE;
2429 else
2431 /* Delete the FontSubstitutes from other locales */
2432 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2434 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2435 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2436 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2437 RegCloseKey(hkey);
2441 if (!done)
2442 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2446 static BOOL init_freetype(void)
2448 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2449 if(!ft_handle) {
2450 WINE_MESSAGE(
2451 "Wine cannot find the FreeType font library. To enable Wine to\n"
2452 "use TrueType fonts please install a version of FreeType greater than\n"
2453 "or equal to 2.0.5.\n"
2454 "http://www.freetype.org\n");
2455 return FALSE;
2458 #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;}
2460 LOAD_FUNCPTR(FT_Vector_Unit)
2461 LOAD_FUNCPTR(FT_Done_Face)
2462 LOAD_FUNCPTR(FT_Get_Char_Index)
2463 LOAD_FUNCPTR(FT_Get_Module)
2464 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2465 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2466 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2467 LOAD_FUNCPTR(FT_Init_FreeType)
2468 LOAD_FUNCPTR(FT_Load_Glyph)
2469 LOAD_FUNCPTR(FT_Matrix_Multiply)
2470 #ifndef FT_MULFIX_INLINED
2471 LOAD_FUNCPTR(FT_MulFix)
2472 #endif
2473 LOAD_FUNCPTR(FT_New_Face)
2474 LOAD_FUNCPTR(FT_New_Memory_Face)
2475 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2476 LOAD_FUNCPTR(FT_Outline_Transform)
2477 LOAD_FUNCPTR(FT_Outline_Translate)
2478 LOAD_FUNCPTR(FT_Select_Charmap)
2479 LOAD_FUNCPTR(FT_Set_Charmap)
2480 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2481 LOAD_FUNCPTR(FT_Vector_Transform)
2483 #undef LOAD_FUNCPTR
2484 /* Don't warn if these ones are missing */
2485 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2486 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2487 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2488 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2489 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2490 #ifdef HAVE_FREETYPE_FTWINFNT_H
2491 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2492 #endif
2493 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2494 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2495 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2496 <= 2.0.3 has FT_Sqrt64 */
2497 goto sym_not_found;
2500 if(pFT_Init_FreeType(&library) != 0) {
2501 ERR("Can't init FreeType library\n");
2502 wine_dlclose(ft_handle, NULL, 0);
2503 ft_handle = NULL;
2504 return FALSE;
2506 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2507 if (pFT_Library_Version)
2508 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2510 if (FT_Version.major<=0)
2512 FT_Version.major=2;
2513 FT_Version.minor=0;
2514 FT_Version.patch=5;
2516 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2517 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2518 ((FT_Version.minor << 8) & 0x00ff00) |
2519 ((FT_Version.patch ) & 0x0000ff);
2521 return TRUE;
2523 sym_not_found:
2524 WINE_MESSAGE(
2525 "Wine cannot find certain functions that it needs inside the FreeType\n"
2526 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2527 "FreeType to at least version 2.0.5.\n"
2528 "http://www.freetype.org\n");
2529 wine_dlclose(ft_handle, NULL, 0);
2530 ft_handle = NULL;
2531 return FALSE;
2534 /*************************************************************
2535 * WineEngInit
2537 * Initialize FreeType library and create a list of available faces
2539 BOOL WineEngInit(void)
2541 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2542 static const WCHAR pathW[] = {'P','a','t','h',0};
2543 HKEY hkey;
2544 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2545 LPVOID data;
2546 WCHAR windowsdir[MAX_PATH];
2547 char *unixname;
2548 HANDLE font_mutex;
2549 const char *data_dir;
2551 TRACE("\n");
2553 /* update locale dependent font info in registry */
2554 update_font_info();
2556 if(!init_freetype()) return FALSE;
2558 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2559 ERR("Failed to create font mutex\n");
2560 return FALSE;
2562 WaitForSingleObject(font_mutex, INFINITE);
2564 delete_external_font_keys();
2566 /* load the system bitmap fonts */
2567 load_system_fonts();
2569 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2570 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2571 strcatW(windowsdir, fontsW);
2572 if((unixname = wine_get_unix_file_name(windowsdir)))
2574 ReadFontDir(unixname, FALSE);
2575 HeapFree(GetProcessHeap(), 0, unixname);
2578 /* load the system truetype fonts */
2579 data_dir = wine_get_data_dir();
2580 if (!data_dir) data_dir = wine_get_build_dir();
2581 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2582 strcpy(unixname, data_dir);
2583 strcat(unixname, "/fonts/");
2584 ReadFontDir(unixname, TRUE);
2585 HeapFree(GetProcessHeap(), 0, unixname);
2588 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2589 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2590 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2591 will skip these. */
2592 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2593 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2594 &hkey) == ERROR_SUCCESS) {
2595 LPWSTR valueW;
2596 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2597 &valuelen, &datalen, NULL, NULL);
2599 valuelen++; /* returned value doesn't include room for '\0' */
2600 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2601 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2602 if (valueW && data)
2604 dlen = datalen * sizeof(WCHAR);
2605 vlen = valuelen;
2606 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2607 &dlen) == ERROR_SUCCESS) {
2608 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2610 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2612 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2613 HeapFree(GetProcessHeap(), 0, unixname);
2616 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2618 WCHAR pathW[MAX_PATH];
2619 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2620 BOOL added = FALSE;
2622 sprintfW(pathW, fmtW, windowsdir, data);
2623 if((unixname = wine_get_unix_file_name(pathW)))
2625 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2626 HeapFree(GetProcessHeap(), 0, unixname);
2628 if (!added)
2629 load_font_from_data_dir(data);
2631 /* reset dlen and vlen */
2632 dlen = datalen;
2633 vlen = valuelen;
2636 HeapFree(GetProcessHeap(), 0, data);
2637 HeapFree(GetProcessHeap(), 0, valueW);
2638 RegCloseKey(hkey);
2641 load_fontconfig_fonts();
2643 /* then look in any directories that we've specified in the config file */
2644 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2645 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2647 DWORD len;
2648 LPWSTR valueW;
2649 LPSTR valueA, ptr;
2651 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2653 len += sizeof(WCHAR);
2654 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2655 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2657 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2658 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2659 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2660 TRACE( "got font path %s\n", debugstr_a(valueA) );
2661 ptr = valueA;
2662 while (ptr)
2664 LPSTR next = strchr( ptr, ':' );
2665 if (next) *next++ = 0;
2666 ReadFontDir( ptr, TRUE );
2667 ptr = next;
2669 HeapFree( GetProcessHeap(), 0, valueA );
2671 HeapFree( GetProcessHeap(), 0, valueW );
2673 RegCloseKey(hkey);
2676 DumpFontList();
2677 LoadSubstList();
2678 DumpSubstList();
2679 LoadReplaceList();
2680 update_reg_entries();
2682 init_system_links();
2684 ReleaseMutex(font_mutex);
2685 return TRUE;
2689 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2691 TT_OS2 *pOS2;
2692 TT_HoriHeader *pHori;
2694 LONG ppem;
2696 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2697 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2699 if(height == 0) height = 16;
2701 /* Calc. height of EM square:
2703 * For +ve lfHeight we have
2704 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2705 * Re-arranging gives:
2706 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2708 * For -ve lfHeight we have
2709 * |lfHeight| = ppem
2710 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2711 * with il = winAscent + winDescent - units_per_em]
2715 if(height > 0) {
2716 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2717 ppem = MulDiv(ft_face->units_per_EM, height,
2718 pHori->Ascender - pHori->Descender);
2719 else
2720 ppem = MulDiv(ft_face->units_per_EM, height,
2721 pOS2->usWinAscent + pOS2->usWinDescent);
2723 else
2724 ppem = -height;
2726 return ppem;
2729 static struct font_mapping *map_font_file( const char *name )
2731 struct font_mapping *mapping;
2732 struct stat st;
2733 int fd;
2735 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2736 if (fstat( fd, &st ) == -1) goto error;
2738 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2740 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2742 mapping->refcount++;
2743 close( fd );
2744 return mapping;
2747 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2748 goto error;
2750 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2751 close( fd );
2753 if (mapping->data == MAP_FAILED)
2755 HeapFree( GetProcessHeap(), 0, mapping );
2756 return NULL;
2758 mapping->refcount = 1;
2759 mapping->dev = st.st_dev;
2760 mapping->ino = st.st_ino;
2761 mapping->size = st.st_size;
2762 list_add_tail( &mappings_list, &mapping->entry );
2763 return mapping;
2765 error:
2766 close( fd );
2767 return NULL;
2770 static void unmap_font_file( struct font_mapping *mapping )
2772 if (!--mapping->refcount)
2774 list_remove( &mapping->entry );
2775 munmap( mapping->data, mapping->size );
2776 HeapFree( GetProcessHeap(), 0, mapping );
2780 static LONG load_VDMX(GdiFont*, LONG);
2782 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2784 FT_Error err;
2785 FT_Face ft_face;
2786 void *data_ptr;
2787 DWORD data_size;
2789 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2791 if (face->file)
2793 if (!(font->mapping = map_font_file( face->file )))
2795 WARN("failed to map %s\n", debugstr_a(face->file));
2796 return 0;
2798 data_ptr = font->mapping->data;
2799 data_size = font->mapping->size;
2801 else
2803 data_ptr = face->font_data_ptr;
2804 data_size = face->font_data_size;
2807 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2808 if(err) {
2809 ERR("FT_New_Face rets %d\n", err);
2810 return 0;
2813 /* set it here, as load_VDMX needs it */
2814 font->ft_face = ft_face;
2816 if(FT_IS_SCALABLE(ft_face)) {
2817 /* load the VDMX table if we have one */
2818 font->ppem = load_VDMX(font, height);
2819 if(font->ppem == 0)
2820 font->ppem = calc_ppem_for_height(ft_face, height);
2821 TRACE("height %d => ppem %d\n", height, font->ppem);
2823 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2824 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2825 } else {
2826 font->ppem = height;
2827 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2828 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2830 return ft_face;
2834 static int get_nearest_charset(Face *face, int *cp)
2836 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2837 a single face with the requested charset. The idea is to check if
2838 the selected font supports the current ANSI codepage, if it does
2839 return the corresponding charset, else return the first charset */
2841 CHARSETINFO csi;
2842 int acp = GetACP(), i;
2843 DWORD fs0;
2845 *cp = acp;
2846 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2847 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2848 return csi.ciCharset;
2850 for(i = 0; i < 32; i++) {
2851 fs0 = 1L << i;
2852 if(face->fs.fsCsb[0] & fs0) {
2853 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2854 *cp = csi.ciACP;
2855 return csi.ciCharset;
2857 else
2858 FIXME("TCI failing on %x\n", fs0);
2862 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2863 face->fs.fsCsb[0], face->file);
2864 *cp = acp;
2865 return DEFAULT_CHARSET;
2868 static GdiFont *alloc_font(void)
2870 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2871 ret->gmsize = 1;
2872 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2873 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2874 ret->potm = NULL;
2875 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2876 ret->total_kern_pairs = (DWORD)-1;
2877 ret->kern_pairs = NULL;
2878 list_init(&ret->hfontlist);
2879 list_init(&ret->child_fonts);
2880 return ret;
2883 static void free_font(GdiFont *font)
2885 struct list *cursor, *cursor2;
2886 int i;
2888 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2890 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2891 struct list *first_hfont;
2892 HFONTLIST *hfontlist;
2893 list_remove(cursor);
2894 if(child->font)
2896 first_hfont = list_head(&child->font->hfontlist);
2897 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2898 DeleteObject(hfontlist->hfont);
2899 HeapFree(GetProcessHeap(), 0, hfontlist);
2900 free_font(child->font);
2902 HeapFree(GetProcessHeap(), 0, child);
2905 if (font->ft_face) pFT_Done_Face(font->ft_face);
2906 if (font->mapping) unmap_font_file( font->mapping );
2907 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2908 HeapFree(GetProcessHeap(), 0, font->potm);
2909 HeapFree(GetProcessHeap(), 0, font->name);
2910 for (i = 0; i < font->gmsize; i++)
2911 HeapFree(GetProcessHeap(),0,font->gm[i]);
2912 HeapFree(GetProcessHeap(), 0, font->gm);
2913 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2914 HeapFree(GetProcessHeap(), 0, font);
2918 /*************************************************************
2919 * load_VDMX
2921 * load the vdmx entry for the specified height
2924 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2925 ( ( (FT_ULong)_x4 << 24 ) | \
2926 ( (FT_ULong)_x3 << 16 ) | \
2927 ( (FT_ULong)_x2 << 8 ) | \
2928 (FT_ULong)_x1 )
2930 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2932 typedef struct {
2933 BYTE bCharSet;
2934 BYTE xRatio;
2935 BYTE yStartRatio;
2936 BYTE yEndRatio;
2937 } Ratios;
2939 typedef struct {
2940 WORD recs;
2941 BYTE startsz;
2942 BYTE endsz;
2943 } VDMX_group;
2945 static LONG load_VDMX(GdiFont *font, LONG height)
2947 WORD hdr[3], tmp;
2948 VDMX_group group;
2949 BYTE devXRatio, devYRatio;
2950 USHORT numRecs, numRatios;
2951 DWORD result, offset = -1;
2952 LONG ppem = 0;
2953 int i;
2955 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2957 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2958 return ppem;
2960 /* FIXME: need the real device aspect ratio */
2961 devXRatio = 1;
2962 devYRatio = 1;
2964 numRecs = GET_BE_WORD(hdr[1]);
2965 numRatios = GET_BE_WORD(hdr[2]);
2967 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2968 for(i = 0; i < numRatios; i++) {
2969 Ratios ratio;
2971 offset = (3 * 2) + (i * sizeof(Ratios));
2972 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2973 offset = -1;
2975 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2977 if((ratio.xRatio == 0 &&
2978 ratio.yStartRatio == 0 &&
2979 ratio.yEndRatio == 0) ||
2980 (devXRatio == ratio.xRatio &&
2981 devYRatio >= ratio.yStartRatio &&
2982 devYRatio <= ratio.yEndRatio))
2984 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2985 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2986 offset = GET_BE_WORD(tmp);
2987 break;
2991 if(offset == -1) {
2992 FIXME("No suitable ratio found\n");
2993 return ppem;
2996 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2997 USHORT recs;
2998 BYTE startsz, endsz;
2999 WORD *vTable;
3001 recs = GET_BE_WORD(group.recs);
3002 startsz = group.startsz;
3003 endsz = group.endsz;
3005 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3007 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3008 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3009 if(result == GDI_ERROR) {
3010 FIXME("Failed to retrieve vTable\n");
3011 goto end;
3014 if(height > 0) {
3015 for(i = 0; i < recs; i++) {
3016 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3017 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3018 ppem = GET_BE_WORD(vTable[i * 3]);
3020 if(yMax + -yMin == height) {
3021 font->yMax = yMax;
3022 font->yMin = yMin;
3023 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3024 break;
3026 if(yMax + -yMin > height) {
3027 if(--i < 0) {
3028 ppem = 0;
3029 goto end; /* failed */
3031 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3032 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3033 ppem = GET_BE_WORD(vTable[i * 3]);
3034 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3035 break;
3038 if(!font->yMax) {
3039 ppem = 0;
3040 TRACE("ppem not found for height %d\n", height);
3042 } else {
3043 ppem = -height;
3044 if(ppem < startsz || ppem > endsz)
3045 goto end;
3047 for(i = 0; i < recs; i++) {
3048 USHORT yPelHeight;
3049 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3051 if(yPelHeight > ppem)
3052 break; /* failed */
3054 if(yPelHeight == ppem) {
3055 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3056 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3057 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3058 break;
3062 end:
3063 HeapFree(GetProcessHeap(), 0, vTable);
3066 return ppem;
3069 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3071 if(font->font_desc.hash != fd->hash) return TRUE;
3072 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3073 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3074 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3075 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3078 static void calc_hash(FONT_DESC *pfd)
3080 DWORD hash = 0, *ptr, two_chars;
3081 WORD *pwc;
3082 unsigned int i;
3084 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3085 hash ^= *ptr;
3086 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3087 hash ^= *ptr;
3088 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3089 two_chars = *ptr;
3090 pwc = (WCHAR *)&two_chars;
3091 if(!*pwc) break;
3092 *pwc = toupperW(*pwc);
3093 pwc++;
3094 *pwc = toupperW(*pwc);
3095 hash ^= two_chars;
3096 if(!*pwc) break;
3098 hash ^= !pfd->can_use_bitmap;
3099 pfd->hash = hash;
3100 return;
3103 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3105 GdiFont *ret;
3106 FONT_DESC fd;
3107 HFONTLIST *hflist;
3108 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3110 fd.lf = *plf;
3111 fd.matrix = *pmat;
3112 fd.can_use_bitmap = can_use_bitmap;
3113 calc_hash(&fd);
3115 /* try the in-use list */
3116 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3117 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3118 if(!fontcmp(ret, &fd)) {
3119 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3120 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3121 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3122 if(hflist->hfont == hfont)
3123 return ret;
3125 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3126 hflist->hfont = hfont;
3127 list_add_head(&ret->hfontlist, &hflist->entry);
3128 return ret;
3132 /* then the unused list */
3133 font_elem_ptr = list_head(&unused_gdi_font_list);
3134 while(font_elem_ptr) {
3135 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3136 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3137 if(!fontcmp(ret, &fd)) {
3138 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3139 assert(list_empty(&ret->hfontlist));
3140 TRACE("Found %p in unused list\n", ret);
3141 list_remove(&ret->entry);
3142 list_add_head(&gdi_font_list, &ret->entry);
3143 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3144 hflist->hfont = hfont;
3145 list_add_head(&ret->hfontlist, &hflist->entry);
3146 return ret;
3149 return NULL;
3152 static void add_to_cache(GdiFont *font)
3154 static DWORD cache_num = 1;
3156 font->cache_num = cache_num++;
3157 list_add_head(&gdi_font_list, &font->entry);
3160 /*************************************************************
3161 * create_child_font_list
3163 static BOOL create_child_font_list(GdiFont *font)
3165 BOOL ret = FALSE;
3166 SYSTEM_LINKS *font_link;
3167 CHILD_FONT *font_link_entry, *new_child;
3169 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3171 if(!strcmpW(font_link->font_name, font->name))
3173 TRACE("found entry in system list\n");
3174 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3176 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3177 new_child->face = font_link_entry->face;
3178 new_child->font = NULL;
3179 list_add_tail(&font->child_fonts, &new_child->entry);
3180 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3182 ret = TRUE;
3183 break;
3187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3188 * Sans Serif. This is how asian windows get default fallbacks for fonts
3190 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3191 font->charset != OEM_CHARSET &&
3192 strcmpW(font->name,szDefaultFallbackLink) != 0)
3193 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3195 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3197 TRACE("found entry in default fallback list\n");
3198 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3200 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3201 new_child->face = font_link_entry->face;
3202 new_child->font = NULL;
3203 list_add_tail(&font->child_fonts, &new_child->entry);
3204 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3206 ret = TRUE;
3207 break;
3211 return ret;
3214 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3216 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3218 if (pFT_Set_Charmap)
3220 FT_Int i;
3221 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3223 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3225 for (i = 0; i < ft_face->num_charmaps; i++)
3227 if (ft_face->charmaps[i]->encoding == encoding)
3229 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3230 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3232 switch (ft_face->charmaps[i]->platform_id)
3234 default:
3235 cmap_def = ft_face->charmaps[i];
3236 break;
3237 case 0: /* Apple Unicode */
3238 cmap0 = ft_face->charmaps[i];
3239 break;
3240 case 1: /* Macintosh */
3241 cmap1 = ft_face->charmaps[i];
3242 break;
3243 case 2: /* ISO */
3244 cmap2 = ft_face->charmaps[i];
3245 break;
3246 case 3: /* Microsoft */
3247 cmap3 = ft_face->charmaps[i];
3248 break;
3252 if (cmap3) /* prefer Microsoft cmap table */
3253 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3254 else if (cmap1)
3255 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3256 else if (cmap2)
3257 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3258 else if (cmap0)
3259 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3260 else if (cmap_def)
3261 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3263 return ft_err == FT_Err_Ok;
3266 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3269 /*************************************************************
3270 * WineEngCreateFontInstance
3273 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3275 GdiFont *ret;
3276 Face *face, *best, *best_bitmap;
3277 Family *family, *last_resort_family;
3278 struct list *family_elem_ptr, *face_elem_ptr;
3279 INT height, width = 0;
3280 unsigned int score = 0, new_score;
3281 signed int diff = 0, newdiff;
3282 BOOL bd, it, can_use_bitmap;
3283 LOGFONTW lf;
3284 CHARSETINFO csi;
3285 HFONTLIST *hflist;
3286 FMAT2 dcmat;
3287 FontSubst *psub = NULL;
3289 EnterCriticalSection( &freetype_cs );
3291 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3293 struct list *first_hfont = list_head(&ret->hfontlist);
3294 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3295 if(hflist->hfont == hfont)
3297 LeaveCriticalSection( &freetype_cs );
3298 return ret;
3302 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3304 LeaveCriticalSection( &freetype_cs );
3305 return NULL;
3307 lf.lfWidth = abs(lf.lfWidth);
3309 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3311 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3312 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3313 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3314 lf.lfEscapement);
3316 if(dc->GraphicsMode == GM_ADVANCED)
3317 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3318 else
3320 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3321 font scaling abilities. */
3322 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3323 dcmat.eM21 = dcmat.eM12 = 0;
3326 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3327 dcmat.eM21, dcmat.eM22);
3329 /* check the cache first */
3330 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3331 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3332 LeaveCriticalSection( &freetype_cs );
3333 return ret;
3336 TRACE("not in cache\n");
3337 if(list_empty(&font_list)) /* No fonts installed */
3339 TRACE("No fonts installed\n");
3340 LeaveCriticalSection( &freetype_cs );
3341 return NULL;
3343 if(!have_installed_roman_font)
3345 TRACE("No roman font installed\n");
3346 LeaveCriticalSection( &freetype_cs );
3347 return NULL;
3350 ret = alloc_font();
3352 ret->font_desc.matrix = dcmat;
3353 ret->font_desc.lf = lf;
3354 ret->font_desc.can_use_bitmap = can_use_bitmap;
3355 calc_hash(&ret->font_desc);
3356 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3357 hflist->hfont = hfont;
3358 list_add_head(&ret->hfontlist, &hflist->entry);
3360 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3361 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3362 original value lfCharSet. Note this is a special case for
3363 Symbol and doesn't happen at least for "Wingdings*" */
3365 if(!strcmpiW(lf.lfFaceName, SymbolW))
3366 lf.lfCharSet = SYMBOL_CHARSET;
3368 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3369 switch(lf.lfCharSet) {
3370 case DEFAULT_CHARSET:
3371 csi.fs.fsCsb[0] = 0;
3372 break;
3373 default:
3374 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3375 csi.fs.fsCsb[0] = 0;
3376 break;
3380 family = NULL;
3381 if(lf.lfFaceName[0] != '\0') {
3382 SYSTEM_LINKS *font_link;
3383 CHILD_FONT *font_link_entry;
3384 LPWSTR FaceName = lf.lfFaceName;
3387 * Check for a leading '@' this signals that the font is being
3388 * requested in tategaki mode (vertical writing substitution) but
3389 * does not affect the fontface that is to be selected.
3391 if (lf.lfFaceName[0]=='@')
3392 FaceName = &lf.lfFaceName[1];
3394 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3396 if(psub) {
3397 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3398 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3399 if (psub->to.charset != -1)
3400 lf.lfCharSet = psub->to.charset;
3403 /* We want a match on name and charset or just name if
3404 charset was DEFAULT_CHARSET. If the latter then
3405 we fixup the returned charset later in get_nearest_charset
3406 where we'll either use the charset of the current ansi codepage
3407 or if that's unavailable the first charset that the font supports.
3409 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3410 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3411 if (!strcmpiW(family->FamilyName, FaceName) ||
3412 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3414 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3415 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3416 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3417 if(face->scalable || can_use_bitmap)
3418 goto found;
3424 * Try check the SystemLink list first for a replacement font.
3425 * We may find good replacements there.
3427 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3429 if(!strcmpiW(font_link->font_name, FaceName))
3431 TRACE("found entry in system list\n");
3432 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3434 face = font_link_entry->face;
3435 family = face->family;
3436 if(csi.fs.fsCsb[0] &
3437 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3439 if(face->scalable || can_use_bitmap)
3440 goto found;
3447 psub = NULL; /* substitution is no more relevant */
3449 /* If requested charset was DEFAULT_CHARSET then try using charset
3450 corresponding to the current ansi codepage */
3451 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3453 INT acp = GetACP();
3454 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3455 FIXME("TCI failed on codepage %d\n", acp);
3456 csi.fs.fsCsb[0] = 0;
3457 } else
3458 lf.lfCharSet = csi.ciCharset;
3461 /* Face families are in the top 4 bits of lfPitchAndFamily,
3462 so mask with 0xF0 before testing */
3464 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3465 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3466 strcpyW(lf.lfFaceName, defFixed);
3467 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3468 strcpyW(lf.lfFaceName, defSerif);
3469 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3470 strcpyW(lf.lfFaceName, defSans);
3471 else
3472 strcpyW(lf.lfFaceName, defSans);
3473 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3474 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3475 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3476 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3477 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3478 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3479 if(face->scalable || can_use_bitmap)
3480 goto found;
3485 last_resort_family = NULL;
3486 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3487 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3488 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3489 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3490 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3491 if(face->scalable)
3492 goto found;
3493 if(can_use_bitmap && !last_resort_family)
3494 last_resort_family = family;
3499 if(last_resort_family) {
3500 family = last_resort_family;
3501 csi.fs.fsCsb[0] = 0;
3502 goto found;
3505 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3506 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3507 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3508 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3509 if(face->scalable) {
3510 csi.fs.fsCsb[0] = 0;
3511 WARN("just using first face for now\n");
3512 goto found;
3514 if(can_use_bitmap && !last_resort_family)
3515 last_resort_family = family;
3518 if(!last_resort_family) {
3519 FIXME("can't find a single appropriate font - bailing\n");
3520 free_font(ret);
3521 LeaveCriticalSection( &freetype_cs );
3522 return NULL;
3525 WARN("could only find a bitmap font - this will probably look awful!\n");
3526 family = last_resort_family;
3527 csi.fs.fsCsb[0] = 0;
3529 found:
3530 it = lf.lfItalic ? 1 : 0;
3531 bd = lf.lfWeight > 550 ? 1 : 0;
3533 height = lf.lfHeight;
3535 face = best = best_bitmap = NULL;
3536 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3538 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3540 BOOL italic, bold;
3542 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3543 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3544 new_score = (italic ^ it) + (bold ^ bd);
3545 if(!best || new_score <= score)
3547 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3548 italic, bold, it, bd);
3549 score = new_score;
3550 best = face;
3551 if(best->scalable && score == 0) break;
3552 if(!best->scalable)
3554 if(height > 0)
3555 newdiff = height - (signed int)(best->size.height);
3556 else
3557 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3558 if(!best_bitmap || new_score < score ||
3559 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3561 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3562 diff = newdiff;
3563 best_bitmap = best;
3564 if(score == 0 && diff == 0) break;
3570 if(best)
3571 face = best->scalable ? best : best_bitmap;
3572 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3573 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3575 ret->fs = face->fs;
3577 if(csi.fs.fsCsb[0]) {
3578 ret->charset = lf.lfCharSet;
3579 ret->codepage = csi.ciACP;
3581 else
3582 ret->charset = get_nearest_charset(face, &ret->codepage);
3584 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3585 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3587 ret->aveWidth = height ? lf.lfWidth : 0;
3589 if(!face->scalable) {
3590 /* Windows uses integer scaling factors for bitmap fonts */
3591 INT scale, scaled_height;
3593 /* FIXME: rotation of bitmap fonts is ignored */
3594 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3595 if (ret->aveWidth)
3596 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3597 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3599 if (height != 0) height = diff;
3600 height += face->size.height;
3602 scale = (height + face->size.height - 1) / face->size.height;
3603 scaled_height = scale * face->size.height;
3604 /* XP allows not more than 10% deviation */
3605 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3606 ret->scale_y = scale;
3608 width = face->size.x_ppem >> 6;
3609 height = face->size.y_ppem >> 6;
3611 else
3612 ret->scale_y = 1.0;
3613 TRACE("font scale y: %f\n", ret->scale_y);
3615 ret->ft_face = OpenFontFace(ret, face, width, height);
3617 if (!ret->ft_face)
3619 free_font( ret );
3620 LeaveCriticalSection( &freetype_cs );
3621 return 0;
3624 ret->ntmFlags = face->ntmFlags;
3626 if (ret->charset == SYMBOL_CHARSET &&
3627 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3628 /* No ops */
3630 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3631 /* No ops */
3633 else {
3634 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3637 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3638 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3639 ret->underline = lf.lfUnderline ? 0xff : 0;
3640 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3641 create_child_font_list(ret);
3643 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3645 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3646 if (length != GDI_ERROR)
3648 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3649 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3650 TRACE("Loaded GSUB table of %i bytes\n",length);
3654 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3656 add_to_cache(ret);
3657 LeaveCriticalSection( &freetype_cs );
3658 return ret;
3661 static void dump_gdi_font_list(void)
3663 GdiFont *gdiFont;
3664 struct list *elem_ptr;
3666 TRACE("---------- gdiFont Cache ----------\n");
3667 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3668 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3669 TRACE("gdiFont=%p %s %d\n",
3670 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3673 TRACE("---------- Unused gdiFont Cache ----------\n");
3674 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3675 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3676 TRACE("gdiFont=%p %s %d\n",
3677 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3681 /*************************************************************
3682 * WineEngDestroyFontInstance
3684 * free the gdiFont associated with this handle
3687 BOOL WineEngDestroyFontInstance(HFONT handle)
3689 GdiFont *gdiFont;
3690 HFONTLIST *hflist;
3691 BOOL ret = FALSE;
3692 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3693 int i = 0;
3695 EnterCriticalSection( &freetype_cs );
3697 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3699 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3700 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3701 if(hflist->hfont == handle)
3703 TRACE("removing child font %p from child list\n", gdiFont);
3704 list_remove(&gdiFont->entry);
3705 LeaveCriticalSection( &freetype_cs );
3706 return TRUE;
3710 TRACE("destroying hfont=%p\n", handle);
3711 if(TRACE_ON(font))
3712 dump_gdi_font_list();
3714 font_elem_ptr = list_head(&gdi_font_list);
3715 while(font_elem_ptr) {
3716 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3717 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3719 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3720 while(hfontlist_elem_ptr) {
3721 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3722 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3723 if(hflist->hfont == handle) {
3724 list_remove(&hflist->entry);
3725 HeapFree(GetProcessHeap(), 0, hflist);
3726 ret = TRUE;
3729 if(list_empty(&gdiFont->hfontlist)) {
3730 TRACE("Moving to Unused list\n");
3731 list_remove(&gdiFont->entry);
3732 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3737 font_elem_ptr = list_head(&unused_gdi_font_list);
3738 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3739 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3740 while(font_elem_ptr) {
3741 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3742 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3743 TRACE("freeing %p\n", gdiFont);
3744 list_remove(&gdiFont->entry);
3745 free_font(gdiFont);
3747 LeaveCriticalSection( &freetype_cs );
3748 return ret;
3751 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3752 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3754 GdiFont *font;
3755 LONG width, height;
3757 if (face->cached_enum_data)
3759 TRACE("Cached\n");
3760 *pelf = face->cached_enum_data->elf;
3761 *pntm = face->cached_enum_data->ntm;
3762 *ptype = face->cached_enum_data->type;
3763 return;
3766 font = alloc_font();
3768 if(face->scalable) {
3769 height = -2048; /* 2048 is the most common em size */
3770 width = 0;
3771 } else {
3772 height = face->size.y_ppem >> 6;
3773 width = face->size.x_ppem >> 6;
3775 font->scale_y = 1.0;
3777 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3779 free_font(font);
3780 return;
3783 font->name = strdupW(face->family->FamilyName);
3784 font->ntmFlags = face->ntmFlags;
3786 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3788 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3790 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3792 lstrcpynW(pelf->elfLogFont.lfFaceName,
3793 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3794 LF_FACESIZE);
3795 lstrcpynW(pelf->elfFullName,
3796 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3797 LF_FULLFACESIZE);
3798 lstrcpynW(pelf->elfStyle,
3799 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3800 LF_FACESIZE);
3802 else
3804 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3806 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3808 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3809 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3810 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3813 pntm->ntmTm.ntmFlags = face->ntmFlags;
3814 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3815 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3816 pntm->ntmFontSig = face->fs;
3818 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3820 pelf->elfLogFont.lfEscapement = 0;
3821 pelf->elfLogFont.lfOrientation = 0;
3822 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3823 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3824 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3825 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3826 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3827 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3828 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3829 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3830 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3831 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3832 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3834 *ptype = 0;
3835 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3836 *ptype |= TRUETYPE_FONTTYPE;
3837 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3838 *ptype |= DEVICE_FONTTYPE;
3839 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3840 *ptype |= RASTER_FONTTYPE;
3842 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3843 if (face->cached_enum_data)
3845 face->cached_enum_data->elf = *pelf;
3846 face->cached_enum_data->ntm = *pntm;
3847 face->cached_enum_data->type = *ptype;
3850 free_font(font);
3853 /*************************************************************
3854 * WineEngEnumFonts
3857 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3859 Family *family;
3860 Face *face;
3861 struct list *family_elem_ptr, *face_elem_ptr;
3862 ENUMLOGFONTEXW elf;
3863 NEWTEXTMETRICEXW ntm;
3864 DWORD type;
3865 FONTSIGNATURE fs;
3866 CHARSETINFO csi;
3867 LOGFONTW lf;
3868 int i;
3870 if (!plf)
3872 lf.lfCharSet = DEFAULT_CHARSET;
3873 lf.lfPitchAndFamily = 0;
3874 lf.lfFaceName[0] = 0;
3875 plf = &lf;
3878 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3880 EnterCriticalSection( &freetype_cs );
3881 if(plf->lfFaceName[0]) {
3882 FontSubst *psub;
3883 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3885 if(psub) {
3886 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3887 debugstr_w(psub->to.name));
3888 lf = *plf;
3889 strcpyW(lf.lfFaceName, psub->to.name);
3890 plf = &lf;
3893 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3894 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3895 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3896 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3897 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3898 GetEnumStructs(face, &elf, &ntm, &type);
3899 for(i = 0; i < 32; i++) {
3900 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3901 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3902 strcpyW(elf.elfScript, OEM_DOSW);
3903 i = 32; /* break out of loop */
3904 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3905 continue;
3906 else {
3907 fs.fsCsb[0] = 1L << i;
3908 fs.fsCsb[1] = 0;
3909 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3910 TCI_SRCFONTSIG))
3911 csi.ciCharset = DEFAULT_CHARSET;
3912 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3913 if(csi.ciCharset != DEFAULT_CHARSET) {
3914 elf.elfLogFont.lfCharSet =
3915 ntm.ntmTm.tmCharSet = csi.ciCharset;
3916 if(ElfScriptsW[i])
3917 strcpyW(elf.elfScript, ElfScriptsW[i]);
3918 else
3919 FIXME("Unknown elfscript for bit %d\n", i);
3922 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3923 debugstr_w(elf.elfLogFont.lfFaceName),
3924 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3925 csi.ciCharset, type, debugstr_w(elf.elfScript),
3926 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3927 ntm.ntmTm.ntmFlags);
3928 /* release section before callback (FIXME) */
3929 LeaveCriticalSection( &freetype_cs );
3930 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3931 EnterCriticalSection( &freetype_cs );
3936 } else {
3937 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3938 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3939 face_elem_ptr = list_head(&family->faces);
3940 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3941 GetEnumStructs(face, &elf, &ntm, &type);
3942 for(i = 0; i < 32; i++) {
3943 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3944 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3945 strcpyW(elf.elfScript, OEM_DOSW);
3946 i = 32; /* break out of loop */
3947 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3948 continue;
3949 else {
3950 fs.fsCsb[0] = 1L << i;
3951 fs.fsCsb[1] = 0;
3952 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3953 TCI_SRCFONTSIG))
3954 csi.ciCharset = DEFAULT_CHARSET;
3955 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3956 if(csi.ciCharset != DEFAULT_CHARSET) {
3957 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3958 csi.ciCharset;
3959 if(ElfScriptsW[i])
3960 strcpyW(elf.elfScript, ElfScriptsW[i]);
3961 else
3962 FIXME("Unknown elfscript for bit %d\n", i);
3965 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3966 debugstr_w(elf.elfLogFont.lfFaceName),
3967 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3968 csi.ciCharset, type, debugstr_w(elf.elfScript),
3969 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3970 ntm.ntmTm.ntmFlags);
3971 /* release section before callback (FIXME) */
3972 LeaveCriticalSection( &freetype_cs );
3973 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3974 EnterCriticalSection( &freetype_cs );
3978 LeaveCriticalSection( &freetype_cs );
3979 return 1;
3982 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3984 pt->x.value = vec->x >> 6;
3985 pt->x.fract = (vec->x & 0x3f) << 10;
3986 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3987 pt->y.value = vec->y >> 6;
3988 pt->y.fract = (vec->y & 0x3f) << 10;
3989 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3990 return;
3993 /***************************************************
3994 * According to the MSDN documentation on WideCharToMultiByte,
3995 * certain codepages cannot set the default_used parameter.
3996 * This returns TRUE if the codepage can set that parameter, false else
3997 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3999 static BOOL codepage_sets_default_used(UINT codepage)
4001 switch (codepage)
4003 case CP_UTF7:
4004 case CP_UTF8:
4005 case CP_SYMBOL:
4006 return FALSE;
4007 default:
4008 return TRUE;
4013 * GSUB Table handling functions
4016 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4018 const GSUB_CoverageFormat1* cf1;
4020 cf1 = (GSUB_CoverageFormat1*)table;
4022 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4024 int count = GET_BE_WORD(cf1->GlyphCount);
4025 int i;
4026 TRACE("Coverage Format 1, %i glyphs\n",count);
4027 for (i = 0; i < count; i++)
4028 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4029 return i;
4030 return -1;
4032 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4034 const GSUB_CoverageFormat2* cf2;
4035 int i;
4036 int count;
4037 cf2 = (GSUB_CoverageFormat2*)cf1;
4039 count = GET_BE_WORD(cf2->RangeCount);
4040 TRACE("Coverage Format 2, %i ranges\n",count);
4041 for (i = 0; i < count; i++)
4043 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4044 return -1;
4045 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4046 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4048 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4049 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4052 return -1;
4054 else
4055 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4057 return -1;
4060 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4062 const GSUB_ScriptList *script;
4063 const GSUB_Script *deflt = NULL;
4064 int i;
4065 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4067 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4068 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4070 const GSUB_Script *scr;
4071 int offset;
4073 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4074 scr = (GSUB_Script*)((LPBYTE)script + offset);
4076 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4077 return scr;
4078 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4079 deflt = scr;
4081 return deflt;
4084 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4086 int i;
4087 int offset;
4088 const GSUB_LangSys *Lang;
4090 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4092 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4094 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4095 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4097 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4098 return Lang;
4100 offset = GET_BE_WORD(script->DefaultLangSys);
4101 if (offset)
4103 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4104 return Lang;
4106 return NULL;
4109 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4111 int i;
4112 const GSUB_FeatureList *feature;
4113 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4115 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4116 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4118 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4119 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4121 const GSUB_Feature *feat;
4122 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4123 return feat;
4126 return NULL;
4129 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4131 int i;
4132 int offset;
4133 const GSUB_LookupList *lookup;
4134 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4136 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4137 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4139 const GSUB_LookupTable *look;
4140 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4141 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4142 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4143 if (GET_BE_WORD(look->LookupType) != 1)
4144 FIXME("We only handle SubType 1\n");
4145 else
4147 int j;
4149 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4151 const GSUB_SingleSubstFormat1 *ssf1;
4152 offset = GET_BE_WORD(look->SubTable[j]);
4153 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4154 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4156 int offset = GET_BE_WORD(ssf1->Coverage);
4157 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4158 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4160 TRACE(" Glyph 0x%x ->",glyph);
4161 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4162 TRACE(" 0x%x\n",glyph);
4165 else
4167 const GSUB_SingleSubstFormat2 *ssf2;
4168 INT index;
4169 INT offset;
4171 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4172 offset = GET_BE_WORD(ssf1->Coverage);
4173 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4174 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4175 TRACE(" Coverage index %i\n",index);
4176 if (index != -1)
4178 TRACE(" Glyph is 0x%x ->",glyph);
4179 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4180 TRACE("0x%x\n",glyph);
4186 return glyph;
4189 static const char* get_opentype_script(const GdiFont *font)
4192 * I am not sure if this is the correct way to generate our script tag
4195 switch (font->charset)
4197 case ANSI_CHARSET: return "latn";
4198 case BALTIC_CHARSET: return "latn"; /* ?? */
4199 case CHINESEBIG5_CHARSET: return "hani";
4200 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4201 case GB2312_CHARSET: return "hani";
4202 case GREEK_CHARSET: return "grek";
4203 case HANGUL_CHARSET: return "hang";
4204 case RUSSIAN_CHARSET: return "cyrl";
4205 case SHIFTJIS_CHARSET: return "kana";
4206 case TURKISH_CHARSET: return "latn"; /* ?? */
4207 case VIETNAMESE_CHARSET: return "latn";
4208 case JOHAB_CHARSET: return "latn"; /* ?? */
4209 case ARABIC_CHARSET: return "arab";
4210 case HEBREW_CHARSET: return "hebr";
4211 case THAI_CHARSET: return "thai";
4212 default: return "latn";
4216 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4218 const GSUB_Header *header;
4219 const GSUB_Script *script;
4220 const GSUB_LangSys *language;
4221 const GSUB_Feature *feature;
4223 if (!font->GSUB_Table)
4224 return glyph;
4226 header = font->GSUB_Table;
4228 script = GSUB_get_script_table(header, get_opentype_script(font));
4229 if (!script)
4231 TRACE("Script not found\n");
4232 return glyph;
4234 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4235 if (!language)
4237 TRACE("Language not found\n");
4238 return glyph;
4240 feature = GSUB_get_feature(header, language, "vrt2");
4241 if (!feature)
4242 feature = GSUB_get_feature(header, language, "vert");
4243 if (!feature)
4245 TRACE("vrt2/vert feature not found\n");
4246 return glyph;
4248 return GSUB_apply_feature(header, feature, glyph);
4251 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4253 FT_UInt glyphId;
4255 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4256 WCHAR wc = (WCHAR)glyph;
4257 BOOL default_used;
4258 BOOL *default_used_pointer;
4259 FT_UInt ret;
4260 char buf;
4261 default_used_pointer = NULL;
4262 default_used = FALSE;
4263 if (codepage_sets_default_used(font->codepage))
4264 default_used_pointer = &default_used;
4265 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4266 ret = 0;
4267 else
4268 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4269 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4270 return get_GSUB_vert_glyph(font,ret);
4273 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4274 glyph = glyph + 0xf000;
4275 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4276 return get_GSUB_vert_glyph(font,glyphId);
4279 /*************************************************************
4280 * WineEngGetGlyphIndices
4283 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4284 LPWORD pgi, DWORD flags)
4286 int i;
4287 int default_char = -1;
4289 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4291 for(i = 0; i < count; i++)
4293 pgi[i] = get_glyph_index(font, lpstr[i]);
4294 if (pgi[i] == 0)
4296 if (default_char == -1)
4298 if (FT_IS_SFNT(font->ft_face))
4300 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4301 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4303 else
4305 TEXTMETRICW textm;
4306 WineEngGetTextMetrics(font, &textm);
4307 default_char = textm.tmDefaultChar;
4310 pgi[i] = default_char;
4313 return count;
4316 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4318 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4319 return !memcmp(matrix, &identity, sizeof(FMAT2));
4322 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4324 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4325 return !memcmp(matrix, &identity, sizeof(MAT2));
4328 /*************************************************************
4329 * WineEngGetGlyphOutline
4331 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4332 * except that the first parameter is the HWINEENGFONT of the font in
4333 * question rather than an HDC.
4336 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4337 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4338 const MAT2* lpmat)
4340 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4341 FT_Face ft_face = incoming_font->ft_face;
4342 GdiFont *font = incoming_font;
4343 FT_UInt glyph_index;
4344 DWORD width, height, pitch, needed = 0;
4345 FT_Bitmap ft_bitmap;
4346 FT_Error err;
4347 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4348 FT_Angle angle = 0;
4349 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4350 double widthRatio = 1.0;
4351 FT_Matrix transMat = identityMat;
4352 FT_Matrix transMatUnrotated;
4353 BOOL needsTransform = FALSE;
4354 BOOL tategaki = (font->GSUB_Table != NULL);
4355 UINT original_index;
4357 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4358 buflen, buf, lpmat);
4360 TRACE("font transform %f %f %f %f\n",
4361 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4362 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4364 EnterCriticalSection( &freetype_cs );
4366 if(format & GGO_GLYPH_INDEX) {
4367 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4368 original_index = glyph;
4369 format &= ~GGO_GLYPH_INDEX;
4370 } else {
4371 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4372 ft_face = font->ft_face;
4373 original_index = glyph_index;
4376 /* tategaki never appears to happen to lower glyph index */
4377 if (glyph_index < TATEGAKI_LOWER_BOUND )
4378 tategaki = FALSE;
4380 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4381 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4382 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4383 font->gmsize * sizeof(GM*));
4384 } else {
4385 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4386 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4388 *lpgm = FONT_GM(font,original_index)->gm;
4389 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4390 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4391 lpgm->gmCellIncX, lpgm->gmCellIncY);
4392 LeaveCriticalSection( &freetype_cs );
4393 return 1; /* FIXME */
4397 if (!font->gm[original_index / GM_BLOCK_SIZE])
4398 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4400 /* Scaling factor */
4401 if (font->aveWidth)
4403 TEXTMETRICW tm;
4405 WineEngGetTextMetrics(font, &tm);
4407 widthRatio = (double)font->aveWidth;
4408 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4410 else
4411 widthRatio = font->scale_y;
4413 /* Scaling transform */
4414 if (widthRatio != 1.0 || font->scale_y != 1.0)
4416 FT_Matrix scaleMat;
4417 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4418 scaleMat.xy = 0;
4419 scaleMat.yx = 0;
4420 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4422 pFT_Matrix_Multiply(&scaleMat, &transMat);
4423 needsTransform = TRUE;
4426 /* Slant transform */
4427 if (font->fake_italic) {
4428 FT_Matrix slantMat;
4430 slantMat.xx = (1 << 16);
4431 slantMat.xy = ((1 << 16) >> 2);
4432 slantMat.yx = 0;
4433 slantMat.yy = (1 << 16);
4434 pFT_Matrix_Multiply(&slantMat, &transMat);
4435 needsTransform = TRUE;
4438 /* Rotation transform */
4439 transMatUnrotated = transMat;
4440 if(font->orientation && !tategaki) {
4441 FT_Matrix rotationMat;
4442 FT_Vector vecAngle;
4443 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4444 pFT_Vector_Unit(&vecAngle, angle);
4445 rotationMat.xx = vecAngle.x;
4446 rotationMat.xy = -vecAngle.y;
4447 rotationMat.yx = -rotationMat.xy;
4448 rotationMat.yy = rotationMat.xx;
4450 pFT_Matrix_Multiply(&rotationMat, &transMat);
4451 needsTransform = TRUE;
4454 /* World transform */
4455 if (!is_identity_FMAT2(&font->font_desc.matrix))
4457 FT_Matrix worldMat;
4458 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4459 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4460 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4461 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4462 pFT_Matrix_Multiply(&worldMat, &transMat);
4463 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4464 needsTransform = TRUE;
4467 /* Extra transformation specified by caller */
4468 if (lpmat && !is_identity_MAT2(lpmat))
4470 FT_Matrix extraMat;
4471 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4472 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4473 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4474 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4475 pFT_Matrix_Multiply(&extraMat, &transMat);
4476 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4477 needsTransform = TRUE;
4480 if (needsTransform || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP))
4481 load_flags |= FT_LOAD_NO_BITMAP;
4483 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4485 if(err) {
4486 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4487 LeaveCriticalSection( &freetype_cs );
4488 return GDI_ERROR;
4491 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4492 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4494 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4495 lsb = left >> 6;
4496 bbx = (right - left) >> 6;
4498 if(!needsTransform) {
4499 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4500 bottom = (ft_face->glyph->metrics.horiBearingY -
4501 ft_face->glyph->metrics.height) & -64;
4502 lpgm->gmCellIncX = adv;
4503 lpgm->gmCellIncY = 0;
4504 } else {
4505 INT xc, yc;
4506 FT_Vector vec;
4507 for(xc = 0; xc < 2; xc++) {
4508 for(yc = 0; yc < 2; yc++) {
4509 vec.x = (ft_face->glyph->metrics.horiBearingX +
4510 xc * ft_face->glyph->metrics.width);
4511 vec.y = ft_face->glyph->metrics.horiBearingY -
4512 yc * ft_face->glyph->metrics.height;
4513 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4514 pFT_Vector_Transform(&vec, &transMat);
4515 if(xc == 0 && yc == 0) {
4516 left = right = vec.x;
4517 top = bottom = vec.y;
4518 } else {
4519 if(vec.x < left) left = vec.x;
4520 else if(vec.x > right) right = vec.x;
4521 if(vec.y < bottom) bottom = vec.y;
4522 else if(vec.y > top) top = vec.y;
4526 left = left & -64;
4527 right = (right + 63) & -64;
4528 bottom = bottom & -64;
4529 top = (top + 63) & -64;
4531 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4532 vec.x = ft_face->glyph->metrics.horiAdvance;
4533 vec.y = 0;
4534 pFT_Vector_Transform(&vec, &transMat);
4535 lpgm->gmCellIncX = (vec.x+63) >> 6;
4536 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4538 vec.x = ft_face->glyph->metrics.horiAdvance;
4539 vec.y = 0;
4540 pFT_Vector_Transform(&vec, &transMatUnrotated);
4541 adv = (vec.x+63) >> 6;
4543 lpgm->gmBlackBoxX = (right - left) >> 6;
4544 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4545 lpgm->gmptGlyphOrigin.x = left >> 6;
4546 lpgm->gmptGlyphOrigin.y = top >> 6;
4548 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4549 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4550 lpgm->gmCellIncX, lpgm->gmCellIncY);
4552 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4553 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4555 FONT_GM(font,original_index)->gm = *lpgm;
4556 FONT_GM(font,original_index)->adv = adv;
4557 FONT_GM(font,original_index)->lsb = lsb;
4558 FONT_GM(font,original_index)->bbx = bbx;
4559 FONT_GM(font,original_index)->init = TRUE;
4562 if(format == GGO_METRICS)
4564 LeaveCriticalSection( &freetype_cs );
4565 return 1; /* FIXME */
4568 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4569 TRACE("loaded a bitmap\n");
4570 LeaveCriticalSection( &freetype_cs );
4571 return GDI_ERROR;
4574 switch(format) {
4575 case GGO_BITMAP:
4576 width = lpgm->gmBlackBoxX;
4577 height = lpgm->gmBlackBoxY;
4578 pitch = ((width + 31) >> 5) << 2;
4579 needed = pitch * height;
4581 if(!buf || !buflen) break;
4583 switch(ft_face->glyph->format) {
4584 case ft_glyph_format_bitmap:
4586 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4587 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4588 INT h = ft_face->glyph->bitmap.rows;
4589 while(h--) {
4590 memcpy(dst, src, w);
4591 src += ft_face->glyph->bitmap.pitch;
4592 dst += pitch;
4594 break;
4597 case ft_glyph_format_outline:
4598 ft_bitmap.width = width;
4599 ft_bitmap.rows = height;
4600 ft_bitmap.pitch = pitch;
4601 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4602 ft_bitmap.buffer = buf;
4604 if(needsTransform) {
4605 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4608 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4610 /* Note: FreeType will only set 'black' bits for us. */
4611 memset(buf, 0, needed);
4612 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4613 break;
4615 default:
4616 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4617 LeaveCriticalSection( &freetype_cs );
4618 return GDI_ERROR;
4620 break;
4622 case GGO_GRAY2_BITMAP:
4623 case GGO_GRAY4_BITMAP:
4624 case GGO_GRAY8_BITMAP:
4625 case WINE_GGO_GRAY16_BITMAP:
4627 unsigned int mult, row, col;
4628 BYTE *start, *ptr;
4630 width = lpgm->gmBlackBoxX;
4631 height = lpgm->gmBlackBoxY;
4632 pitch = (width + 3) / 4 * 4;
4633 needed = pitch * height;
4635 if(!buf || !buflen) break;
4637 switch(ft_face->glyph->format) {
4638 case ft_glyph_format_bitmap:
4640 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4641 INT h = ft_face->glyph->bitmap.rows;
4642 INT x;
4643 while(h--) {
4644 for(x = 0; x < pitch; x++)
4646 if(x < ft_face->glyph->bitmap.width)
4647 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4648 else
4649 dst[x] = 0;
4651 src += ft_face->glyph->bitmap.pitch;
4652 dst += pitch;
4654 LeaveCriticalSection( &freetype_cs );
4655 return needed;
4657 case ft_glyph_format_outline:
4659 ft_bitmap.width = width;
4660 ft_bitmap.rows = height;
4661 ft_bitmap.pitch = pitch;
4662 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4663 ft_bitmap.buffer = buf;
4665 if(needsTransform)
4666 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4668 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4670 memset(ft_bitmap.buffer, 0, buflen);
4672 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4674 if(format == GGO_GRAY2_BITMAP)
4675 mult = 4;
4676 else if(format == GGO_GRAY4_BITMAP)
4677 mult = 16;
4678 else if(format == GGO_GRAY8_BITMAP)
4679 mult = 64;
4680 else /* format == WINE_GGO_GRAY16_BITMAP */
4682 LeaveCriticalSection( &freetype_cs );
4683 return needed;
4685 break;
4687 default:
4688 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4689 LeaveCriticalSection( &freetype_cs );
4690 return GDI_ERROR;
4693 start = buf;
4694 for(row = 0; row < height; row++) {
4695 ptr = start;
4696 for(col = 0; col < width; col++, ptr++) {
4697 *ptr = (((int)*ptr) * mult + 128) / 256;
4699 start += pitch;
4701 break;
4704 case GGO_NATIVE:
4706 int contour, point = 0, first_pt;
4707 FT_Outline *outline = &ft_face->glyph->outline;
4708 TTPOLYGONHEADER *pph;
4709 TTPOLYCURVE *ppc;
4710 DWORD pph_start, cpfx, type;
4712 if(buflen == 0) buf = NULL;
4714 if (needsTransform && buf) {
4715 pFT_Outline_Transform(outline, &transMat);
4718 for(contour = 0; contour < outline->n_contours; contour++) {
4719 pph_start = needed;
4720 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4721 first_pt = point;
4722 if(buf) {
4723 pph->dwType = TT_POLYGON_TYPE;
4724 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4726 needed += sizeof(*pph);
4727 point++;
4728 while(point <= outline->contours[contour]) {
4729 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4730 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4731 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4732 cpfx = 0;
4733 do {
4734 if(buf)
4735 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4736 cpfx++;
4737 point++;
4738 } while(point <= outline->contours[contour] &&
4739 (outline->tags[point] & FT_Curve_Tag_On) ==
4740 (outline->tags[point-1] & FT_Curve_Tag_On));
4741 /* At the end of a contour Windows adds the start point, but
4742 only for Beziers */
4743 if(point > outline->contours[contour] &&
4744 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4745 if(buf)
4746 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4747 cpfx++;
4748 } else if(point <= outline->contours[contour] &&
4749 outline->tags[point] & FT_Curve_Tag_On) {
4750 /* add closing pt for bezier */
4751 if(buf)
4752 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4753 cpfx++;
4754 point++;
4756 if(buf) {
4757 ppc->wType = type;
4758 ppc->cpfx = cpfx;
4760 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4762 if(buf)
4763 pph->cb = needed - pph_start;
4765 break;
4767 case GGO_BEZIER:
4769 /* Convert the quadratic Beziers to cubic Beziers.
4770 The parametric eqn for a cubic Bezier is, from PLRM:
4771 r(t) = at^3 + bt^2 + ct + r0
4772 with the control points:
4773 r1 = r0 + c/3
4774 r2 = r1 + (c + b)/3
4775 r3 = r0 + c + b + a
4777 A quadratic Beizer has the form:
4778 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4780 So equating powers of t leads to:
4781 r1 = 2/3 p1 + 1/3 p0
4782 r2 = 2/3 p1 + 1/3 p2
4783 and of course r0 = p0, r3 = p2
4786 int contour, point = 0, first_pt;
4787 FT_Outline *outline = &ft_face->glyph->outline;
4788 TTPOLYGONHEADER *pph;
4789 TTPOLYCURVE *ppc;
4790 DWORD pph_start, cpfx, type;
4791 FT_Vector cubic_control[4];
4792 if(buflen == 0) buf = NULL;
4794 if (needsTransform && buf) {
4795 pFT_Outline_Transform(outline, &transMat);
4798 for(contour = 0; contour < outline->n_contours; contour++) {
4799 pph_start = needed;
4800 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4801 first_pt = point;
4802 if(buf) {
4803 pph->dwType = TT_POLYGON_TYPE;
4804 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4806 needed += sizeof(*pph);
4807 point++;
4808 while(point <= outline->contours[contour]) {
4809 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4810 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4811 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4812 cpfx = 0;
4813 do {
4814 if(type == TT_PRIM_LINE) {
4815 if(buf)
4816 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4817 cpfx++;
4818 point++;
4819 } else {
4820 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4821 so cpfx = 3n */
4823 /* FIXME: Possible optimization in endpoint calculation
4824 if there are two consecutive curves */
4825 cubic_control[0] = outline->points[point-1];
4826 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4827 cubic_control[0].x += outline->points[point].x + 1;
4828 cubic_control[0].y += outline->points[point].y + 1;
4829 cubic_control[0].x >>= 1;
4830 cubic_control[0].y >>= 1;
4832 if(point+1 > outline->contours[contour])
4833 cubic_control[3] = outline->points[first_pt];
4834 else {
4835 cubic_control[3] = outline->points[point+1];
4836 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4837 cubic_control[3].x += outline->points[point].x + 1;
4838 cubic_control[3].y += outline->points[point].y + 1;
4839 cubic_control[3].x >>= 1;
4840 cubic_control[3].y >>= 1;
4843 /* r1 = 1/3 p0 + 2/3 p1
4844 r2 = 1/3 p2 + 2/3 p1 */
4845 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4846 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4847 cubic_control[2] = cubic_control[1];
4848 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4849 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4850 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4851 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4852 if(buf) {
4853 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4854 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4855 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4857 cpfx += 3;
4858 point++;
4860 } while(point <= outline->contours[contour] &&
4861 (outline->tags[point] & FT_Curve_Tag_On) ==
4862 (outline->tags[point-1] & FT_Curve_Tag_On));
4863 /* At the end of a contour Windows adds the start point,
4864 but only for Beziers and we've already done that.
4866 if(point <= outline->contours[contour] &&
4867 outline->tags[point] & FT_Curve_Tag_On) {
4868 /* This is the closing pt of a bezier, but we've already
4869 added it, so just inc point and carry on */
4870 point++;
4872 if(buf) {
4873 ppc->wType = type;
4874 ppc->cpfx = cpfx;
4876 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4878 if(buf)
4879 pph->cb = needed - pph_start;
4881 break;
4884 default:
4885 FIXME("Unsupported format %d\n", format);
4886 LeaveCriticalSection( &freetype_cs );
4887 return GDI_ERROR;
4889 LeaveCriticalSection( &freetype_cs );
4890 return needed;
4893 static BOOL get_bitmap_text_metrics(GdiFont *font)
4895 FT_Face ft_face = font->ft_face;
4896 #ifdef HAVE_FREETYPE_FTWINFNT_H
4897 FT_WinFNT_HeaderRec winfnt_header;
4898 #endif
4899 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4900 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4901 font->potm->otmSize = size;
4903 #define TM font->potm->otmTextMetrics
4904 #ifdef HAVE_FREETYPE_FTWINFNT_H
4905 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4907 TM.tmHeight = winfnt_header.pixel_height;
4908 TM.tmAscent = winfnt_header.ascent;
4909 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4910 TM.tmInternalLeading = winfnt_header.internal_leading;
4911 TM.tmExternalLeading = winfnt_header.external_leading;
4912 TM.tmAveCharWidth = winfnt_header.avg_width;
4913 TM.tmMaxCharWidth = winfnt_header.max_width;
4914 TM.tmWeight = winfnt_header.weight;
4915 TM.tmOverhang = 0;
4916 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4917 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4918 TM.tmFirstChar = winfnt_header.first_char;
4919 TM.tmLastChar = winfnt_header.last_char;
4920 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4921 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4922 TM.tmItalic = winfnt_header.italic;
4923 TM.tmUnderlined = font->underline;
4924 TM.tmStruckOut = font->strikeout;
4925 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4926 TM.tmCharSet = winfnt_header.charset;
4928 else
4929 #endif
4931 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4932 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4933 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4934 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4935 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4936 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4937 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4938 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4939 TM.tmOverhang = 0;
4940 TM.tmDigitizedAspectX = 96; /* FIXME */
4941 TM.tmDigitizedAspectY = 96; /* FIXME */
4942 TM.tmFirstChar = 1;
4943 TM.tmLastChar = 255;
4944 TM.tmDefaultChar = 32;
4945 TM.tmBreakChar = 32;
4946 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4947 TM.tmUnderlined = font->underline;
4948 TM.tmStruckOut = font->strikeout;
4949 /* NB inverted meaning of TMPF_FIXED_PITCH */
4950 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4951 TM.tmCharSet = font->charset;
4953 #undef TM
4955 return TRUE;
4959 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4961 double scale_x, scale_y;
4963 if (font->aveWidth)
4965 scale_x = (double)font->aveWidth;
4966 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4968 else
4969 scale_x = font->scale_y;
4971 scale_x *= fabs(font->font_desc.matrix.eM11);
4972 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4974 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4975 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4977 SCALE_Y(ptm->tmHeight);
4978 SCALE_Y(ptm->tmAscent);
4979 SCALE_Y(ptm->tmDescent);
4980 SCALE_Y(ptm->tmInternalLeading);
4981 SCALE_Y(ptm->tmExternalLeading);
4982 SCALE_Y(ptm->tmOverhang);
4984 SCALE_X(ptm->tmAveCharWidth);
4985 SCALE_X(ptm->tmMaxCharWidth);
4987 #undef SCALE_X
4988 #undef SCALE_Y
4991 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4993 double scale_x, scale_y;
4995 if (font->aveWidth)
4997 scale_x = (double)font->aveWidth;
4998 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5000 else
5001 scale_x = font->scale_y;
5003 scale_x *= fabs(font->font_desc.matrix.eM11);
5004 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5006 scale_font_metrics(font, &potm->otmTextMetrics);
5008 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5009 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5011 SCALE_Y(potm->otmAscent);
5012 SCALE_Y(potm->otmDescent);
5013 SCALE_Y(potm->otmLineGap);
5014 SCALE_Y(potm->otmsCapEmHeight);
5015 SCALE_Y(potm->otmsXHeight);
5016 SCALE_Y(potm->otmrcFontBox.top);
5017 SCALE_Y(potm->otmrcFontBox.bottom);
5018 SCALE_X(potm->otmrcFontBox.left);
5019 SCALE_X(potm->otmrcFontBox.right);
5020 SCALE_Y(potm->otmMacAscent);
5021 SCALE_Y(potm->otmMacDescent);
5022 SCALE_Y(potm->otmMacLineGap);
5023 SCALE_X(potm->otmptSubscriptSize.x);
5024 SCALE_Y(potm->otmptSubscriptSize.y);
5025 SCALE_X(potm->otmptSubscriptOffset.x);
5026 SCALE_Y(potm->otmptSubscriptOffset.y);
5027 SCALE_X(potm->otmptSuperscriptSize.x);
5028 SCALE_Y(potm->otmptSuperscriptSize.y);
5029 SCALE_X(potm->otmptSuperscriptOffset.x);
5030 SCALE_Y(potm->otmptSuperscriptOffset.y);
5031 SCALE_Y(potm->otmsStrikeoutSize);
5032 SCALE_Y(potm->otmsStrikeoutPosition);
5033 SCALE_Y(potm->otmsUnderscoreSize);
5034 SCALE_Y(potm->otmsUnderscorePosition);
5036 #undef SCALE_X
5037 #undef SCALE_Y
5040 /*************************************************************
5041 * WineEngGetTextMetrics
5044 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5046 EnterCriticalSection( &freetype_cs );
5047 if(!font->potm) {
5048 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5049 if(!get_bitmap_text_metrics(font))
5051 LeaveCriticalSection( &freetype_cs );
5052 return FALSE;
5055 if(!font->potm)
5057 LeaveCriticalSection( &freetype_cs );
5058 return FALSE;
5060 *ptm = font->potm->otmTextMetrics;
5061 scale_font_metrics(font, ptm);
5062 LeaveCriticalSection( &freetype_cs );
5063 return TRUE;
5067 /*************************************************************
5068 * WineEngGetOutlineTextMetrics
5071 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5072 OUTLINETEXTMETRICW *potm)
5074 FT_Face ft_face = font->ft_face;
5075 UINT needed, lenfam, lensty, ret;
5076 TT_OS2 *pOS2;
5077 TT_HoriHeader *pHori;
5078 TT_Postscript *pPost;
5079 FT_Fixed x_scale, y_scale;
5080 WCHAR *family_nameW, *style_nameW;
5081 static const WCHAR spaceW[] = {' ', '\0'};
5082 char *cp;
5083 INT ascent, descent;
5085 TRACE("font=%p\n", font);
5087 if(!FT_IS_SCALABLE(ft_face))
5088 return 0;
5090 EnterCriticalSection( &freetype_cs );
5092 if(font->potm) {
5093 if(cbSize >= font->potm->otmSize)
5095 memcpy(potm, font->potm, font->potm->otmSize);
5096 scale_outline_font_metrics(font, potm);
5098 LeaveCriticalSection( &freetype_cs );
5099 return font->potm->otmSize;
5103 needed = sizeof(*potm);
5105 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5106 family_nameW = strdupW(font->name);
5108 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5109 * sizeof(WCHAR);
5110 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5111 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5112 style_nameW, lensty/sizeof(WCHAR));
5114 /* These names should be read from the TT name table */
5116 /* length of otmpFamilyName */
5117 needed += lenfam;
5119 /* length of otmpFaceName */
5120 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5121 needed += lenfam; /* just the family name */
5122 } else {
5123 needed += lenfam + lensty; /* family + " " + style */
5126 /* length of otmpStyleName */
5127 needed += lensty;
5129 /* length of otmpFullName */
5130 needed += lenfam + lensty;
5133 x_scale = ft_face->size->metrics.x_scale;
5134 y_scale = ft_face->size->metrics.y_scale;
5136 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5137 if(!pOS2) {
5138 FIXME("Can't find OS/2 table - not TT font?\n");
5139 ret = 0;
5140 goto end;
5143 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5144 if(!pHori) {
5145 FIXME("Can't find HHEA table - not TT font?\n");
5146 ret = 0;
5147 goto end;
5150 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5152 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",
5153 pOS2->usWinAscent, pOS2->usWinDescent,
5154 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5155 ft_face->ascender, ft_face->descender, ft_face->height,
5156 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5157 ft_face->bbox.yMax, ft_face->bbox.yMin);
5159 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5160 font->potm->otmSize = needed;
5162 #define TM font->potm->otmTextMetrics
5164 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5165 ascent = pHori->Ascender;
5166 descent = -pHori->Descender;
5167 } else {
5168 ascent = pOS2->usWinAscent;
5169 descent = pOS2->usWinDescent;
5172 if(font->yMax) {
5173 TM.tmAscent = font->yMax;
5174 TM.tmDescent = -font->yMin;
5175 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5176 } else {
5177 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5178 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5179 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5180 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5183 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5185 /* MSDN says:
5186 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5188 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5189 ((ascent + descent) -
5190 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5192 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5193 if (TM.tmAveCharWidth == 0) {
5194 TM.tmAveCharWidth = 1;
5196 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5197 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5198 TM.tmOverhang = 0;
5199 TM.tmDigitizedAspectX = 300;
5200 TM.tmDigitizedAspectY = 300;
5201 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5202 * symbol range to 0 - f0ff
5204 if (font->charset == SYMBOL_CHARSET)
5206 TM.tmFirstChar = 0;
5207 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5209 else
5211 TM.tmFirstChar = pOS2->usFirstCharIndex;
5212 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5214 TM.tmLastChar = pOS2->usLastCharIndex;
5215 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5216 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5217 TM.tmUnderlined = font->underline;
5218 TM.tmStruckOut = font->strikeout;
5220 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5221 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5222 (pOS2->version == 0xFFFFU ||
5223 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5224 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5225 else
5226 TM.tmPitchAndFamily = 0;
5228 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5229 case PAN_FAMILY_SCRIPT:
5230 TM.tmPitchAndFamily |= FF_SCRIPT;
5231 break;
5232 case PAN_FAMILY_DECORATIVE:
5233 case PAN_FAMILY_PICTORIAL:
5234 TM.tmPitchAndFamily |= FF_DECORATIVE;
5235 break;
5236 case PAN_FAMILY_TEXT_DISPLAY:
5237 if(TM.tmPitchAndFamily == 0) /* fixed */
5238 TM.tmPitchAndFamily = FF_MODERN;
5239 else {
5240 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5241 case PAN_SERIF_NORMAL_SANS:
5242 case PAN_SERIF_OBTUSE_SANS:
5243 case PAN_SERIF_PERP_SANS:
5244 TM.tmPitchAndFamily |= FF_SWISS;
5245 break;
5246 default:
5247 TM.tmPitchAndFamily |= FF_ROMAN;
5250 break;
5251 default:
5252 TM.tmPitchAndFamily |= FF_DONTCARE;
5255 if(FT_IS_SCALABLE(ft_face))
5256 TM.tmPitchAndFamily |= TMPF_VECTOR;
5258 if(FT_IS_SFNT(ft_face))
5260 if (font->ntmFlags & NTM_PS_OPENTYPE)
5261 TM.tmPitchAndFamily |= TMPF_DEVICE;
5262 else
5263 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5266 TM.tmCharSet = font->charset;
5268 font->potm->otmFiller = 0;
5269 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5270 font->potm->otmfsSelection = pOS2->fsSelection;
5271 font->potm->otmfsType = pOS2->fsType;
5272 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5273 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5274 font->potm->otmItalicAngle = 0; /* POST table */
5275 font->potm->otmEMSquare = ft_face->units_per_EM;
5276 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5277 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5278 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5279 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5280 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5281 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5282 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5283 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5284 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5285 font->potm->otmMacAscent = TM.tmAscent;
5286 font->potm->otmMacDescent = -TM.tmDescent;
5287 font->potm->otmMacLineGap = font->potm->otmLineGap;
5288 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5289 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5290 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5291 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5292 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5293 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5294 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5295 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5296 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5297 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5298 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5299 if(!pPost) {
5300 font->potm->otmsUnderscoreSize = 0;
5301 font->potm->otmsUnderscorePosition = 0;
5302 } else {
5303 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5304 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5306 #undef TM
5308 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5309 cp = (char*)font->potm + sizeof(*font->potm);
5310 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5311 strcpyW((WCHAR*)cp, family_nameW);
5312 cp += lenfam;
5313 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5314 strcpyW((WCHAR*)cp, style_nameW);
5315 cp += lensty;
5316 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5317 strcpyW((WCHAR*)cp, family_nameW);
5318 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5319 strcatW((WCHAR*)cp, spaceW);
5320 strcatW((WCHAR*)cp, style_nameW);
5321 cp += lenfam + lensty;
5322 } else
5323 cp += lenfam;
5324 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5325 strcpyW((WCHAR*)cp, family_nameW);
5326 strcatW((WCHAR*)cp, spaceW);
5327 strcatW((WCHAR*)cp, style_nameW);
5328 ret = needed;
5330 if(potm && needed <= cbSize)
5332 memcpy(potm, font->potm, font->potm->otmSize);
5333 scale_outline_font_metrics(font, potm);
5336 end:
5337 HeapFree(GetProcessHeap(), 0, style_nameW);
5338 HeapFree(GetProcessHeap(), 0, family_nameW);
5340 LeaveCriticalSection( &freetype_cs );
5341 return ret;
5344 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5346 HFONTLIST *hfontlist;
5347 child->font = alloc_font();
5348 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5349 if(!child->font->ft_face)
5351 free_font(child->font);
5352 child->font = NULL;
5353 return FALSE;
5356 child->font->ntmFlags = child->face->ntmFlags;
5357 child->font->orientation = font->orientation;
5358 child->font->scale_y = font->scale_y;
5359 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5360 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5361 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5362 child->font->base_font = font;
5363 list_add_head(&child_font_list, &child->font->entry);
5364 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5365 return TRUE;
5368 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5370 FT_UInt g;
5371 CHILD_FONT *child_font;
5373 if(font->base_font)
5374 font = font->base_font;
5376 *linked_font = font;
5378 if((*glyph = get_glyph_index(font, c)))
5379 return TRUE;
5381 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5383 if(!child_font->font)
5384 if(!load_child_font(font, child_font))
5385 continue;
5387 if(!child_font->font->ft_face)
5388 continue;
5389 g = get_glyph_index(child_font->font, c);
5390 if(g)
5392 *glyph = g;
5393 *linked_font = child_font->font;
5394 return TRUE;
5397 return FALSE;
5400 /*************************************************************
5401 * WineEngGetCharWidth
5404 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5405 LPINT buffer)
5407 UINT c;
5408 GLYPHMETRICS gm;
5409 FT_UInt glyph_index;
5410 GdiFont *linked_font;
5412 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5414 EnterCriticalSection( &freetype_cs );
5415 for(c = firstChar; c <= lastChar; c++) {
5416 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5417 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5418 &gm, 0, NULL, NULL);
5419 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5421 LeaveCriticalSection( &freetype_cs );
5422 return TRUE;
5425 /*************************************************************
5426 * WineEngGetCharABCWidths
5429 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5430 LPABC buffer)
5432 UINT c;
5433 GLYPHMETRICS gm;
5434 FT_UInt glyph_index;
5435 GdiFont *linked_font;
5437 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5439 if(!FT_IS_SCALABLE(font->ft_face))
5440 return FALSE;
5442 EnterCriticalSection( &freetype_cs );
5444 for(c = firstChar; c <= lastChar; c++) {
5445 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5446 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5447 &gm, 0, NULL, NULL);
5448 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5449 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5450 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5451 FONT_GM(linked_font,glyph_index)->bbx;
5453 LeaveCriticalSection( &freetype_cs );
5454 return TRUE;
5457 /*************************************************************
5458 * WineEngGetCharABCWidthsI
5461 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5462 LPABC buffer)
5464 UINT c;
5465 GLYPHMETRICS gm;
5466 FT_UInt glyph_index;
5467 GdiFont *linked_font;
5469 if(!FT_HAS_HORIZONTAL(font->ft_face))
5470 return FALSE;
5472 EnterCriticalSection( &freetype_cs );
5474 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5475 if (!pgi)
5476 for(c = firstChar; c < firstChar+count; c++) {
5477 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5478 &gm, 0, NULL, NULL);
5479 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5480 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5481 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5482 - FONT_GM(linked_font,c)->bbx;
5484 else
5485 for(c = 0; c < count; c++) {
5486 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5487 &gm, 0, NULL, NULL);
5488 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5489 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5490 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5491 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5494 LeaveCriticalSection( &freetype_cs );
5495 return TRUE;
5498 /*************************************************************
5499 * WineEngGetTextExtentExPoint
5502 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5503 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5505 INT idx;
5506 INT nfit = 0, ext;
5507 GLYPHMETRICS gm;
5508 TEXTMETRICW tm;
5509 FT_UInt glyph_index;
5510 GdiFont *linked_font;
5512 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5513 max_ext, size);
5515 EnterCriticalSection( &freetype_cs );
5517 size->cx = 0;
5518 WineEngGetTextMetrics(font, &tm);
5519 size->cy = tm.tmHeight;
5521 for(idx = 0; idx < count; idx++) {
5522 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5523 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5524 &gm, 0, NULL, NULL);
5525 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5526 ext = size->cx;
5527 if (! pnfit || ext <= max_ext) {
5528 ++nfit;
5529 if (dxs)
5530 dxs[idx] = ext;
5534 if (pnfit)
5535 *pnfit = nfit;
5537 LeaveCriticalSection( &freetype_cs );
5538 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5539 return TRUE;
5542 /*************************************************************
5543 * WineEngGetTextExtentExPointI
5546 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5547 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5549 INT idx;
5550 INT nfit = 0, ext;
5551 GLYPHMETRICS gm;
5552 TEXTMETRICW tm;
5554 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5556 EnterCriticalSection( &freetype_cs );
5558 size->cx = 0;
5559 WineEngGetTextMetrics(font, &tm);
5560 size->cy = tm.tmHeight;
5562 for(idx = 0; idx < count; idx++) {
5563 WineEngGetGlyphOutline(font, indices[idx],
5564 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5565 NULL);
5566 size->cx += FONT_GM(font,indices[idx])->adv;
5567 ext = size->cx;
5568 if (! pnfit || ext <= max_ext) {
5569 ++nfit;
5570 if (dxs)
5571 dxs[idx] = ext;
5575 if (pnfit)
5576 *pnfit = nfit;
5578 LeaveCriticalSection( &freetype_cs );
5579 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5580 return TRUE;
5583 /*************************************************************
5584 * WineEngGetFontData
5587 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5588 DWORD cbData)
5590 FT_Face ft_face = font->ft_face;
5591 FT_ULong len;
5592 FT_Error err;
5594 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5595 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5596 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5598 if(!FT_IS_SFNT(ft_face))
5599 return GDI_ERROR;
5601 if(!buf || !cbData)
5602 len = 0;
5603 else
5604 len = cbData;
5606 if(table) { /* MS tags differ in endianness from FT ones */
5607 table = table >> 24 | table << 24 |
5608 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5611 /* make sure value of len is the value freetype says it needs */
5612 if(buf && len)
5614 FT_ULong needed = 0;
5615 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5616 if( !err && needed < len) len = needed;
5618 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5620 if(err) {
5621 TRACE("Can't find table %c%c%c%c\n",
5622 /* bytes were reversed */
5623 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5624 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5625 return GDI_ERROR;
5627 return len;
5630 /*************************************************************
5631 * WineEngGetTextFace
5634 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5636 INT n = strlenW(font->name) + 1;
5637 if(str) {
5638 lstrcpynW(str, font->name, count);
5639 return min(count, n);
5640 } else
5641 return n;
5644 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5646 if (fs) *fs = font->fs;
5647 return font->charset;
5650 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5652 GdiFont *font = dc->gdiFont, *linked_font;
5653 struct list *first_hfont;
5654 BOOL ret;
5656 EnterCriticalSection( &freetype_cs );
5657 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5658 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5659 if(font == linked_font)
5660 *new_hfont = dc->hFont;
5661 else
5663 first_hfont = list_head(&linked_font->hfontlist);
5664 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5666 LeaveCriticalSection( &freetype_cs );
5667 return ret;
5670 /* Retrieve a list of supported Unicode ranges for a given font.
5671 * Can be called with NULL gs to calculate the buffer size. Returns
5672 * the number of ranges found.
5674 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5676 DWORD num_ranges = 0;
5678 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5680 FT_UInt glyph_code;
5681 FT_ULong char_code, char_code_prev;
5683 glyph_code = 0;
5684 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5686 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5687 face->num_glyphs, glyph_code, char_code);
5689 if (!glyph_code) return 0;
5691 if (gs)
5693 gs->ranges[0].wcLow = (USHORT)char_code;
5694 gs->ranges[0].cGlyphs = 0;
5695 gs->cGlyphsSupported = 0;
5698 num_ranges = 1;
5699 while (glyph_code)
5701 if (char_code < char_code_prev)
5703 ERR("expected increasing char code from FT_Get_Next_Char\n");
5704 return 0;
5706 if (char_code - char_code_prev > 1)
5708 num_ranges++;
5709 if (gs)
5711 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5712 gs->ranges[num_ranges - 1].cGlyphs = 1;
5713 gs->cGlyphsSupported++;
5716 else if (gs)
5718 gs->ranges[num_ranges - 1].cGlyphs++;
5719 gs->cGlyphsSupported++;
5721 char_code_prev = char_code;
5722 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5725 else
5726 FIXME("encoding %u not supported\n", face->charmap->encoding);
5728 return num_ranges;
5731 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5733 DWORD size = 0;
5734 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5736 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5737 if (glyphset)
5739 glyphset->cbThis = size;
5740 glyphset->cRanges = num_ranges;
5742 return size;
5745 /*************************************************************
5746 * FontIsLinked
5748 BOOL WineEngFontIsLinked(GdiFont *font)
5750 BOOL ret;
5751 EnterCriticalSection( &freetype_cs );
5752 ret = !list_empty(&font->child_fonts);
5753 LeaveCriticalSection( &freetype_cs );
5754 return ret;
5757 static BOOL is_hinting_enabled(void)
5759 /* Use the >= 2.2.0 function if available */
5760 if(pFT_Get_TrueType_Engine_Type)
5762 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5763 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5765 #ifdef FT_DRIVER_HAS_HINTER
5766 else
5768 FT_Module mod;
5770 /* otherwise if we've been compiled with < 2.2.0 headers
5771 use the internal macro */
5772 mod = pFT_Get_Module(library, "truetype");
5773 if(mod && FT_DRIVER_HAS_HINTER(mod))
5774 return TRUE;
5776 #endif
5778 return FALSE;
5781 /*************************************************************************
5782 * GetRasterizerCaps (GDI32.@)
5784 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5786 static int hinting = -1;
5788 if(hinting == -1)
5790 hinting = is_hinting_enabled();
5791 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5794 lprs->nSize = sizeof(RASTERIZER_STATUS);
5795 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5796 lprs->nLanguageID = 0;
5797 return TRUE;
5800 /*************************************************************
5801 * WineEngRealizationInfo
5803 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5805 FIXME("(%p, %p): stub!\n", font, info);
5807 info->flags = 1;
5808 if(FT_IS_SCALABLE(font->ft_face))
5809 info->flags |= 2;
5811 info->cache_num = font->cache_num;
5812 info->unknown2 = -1;
5813 return TRUE;
5816 /*************************************************************************
5817 * Kerning support for TrueType fonts
5819 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5821 struct TT_kern_table
5823 USHORT version;
5824 USHORT nTables;
5827 struct TT_kern_subtable
5829 USHORT version;
5830 USHORT length;
5831 union
5833 USHORT word;
5834 struct
5836 USHORT horizontal : 1;
5837 USHORT minimum : 1;
5838 USHORT cross_stream: 1;
5839 USHORT override : 1;
5840 USHORT reserved1 : 4;
5841 USHORT format : 8;
5842 } bits;
5843 } coverage;
5846 struct TT_format0_kern_subtable
5848 USHORT nPairs;
5849 USHORT searchRange;
5850 USHORT entrySelector;
5851 USHORT rangeShift;
5854 struct TT_kern_pair
5856 USHORT left;
5857 USHORT right;
5858 short value;
5861 static DWORD parse_format0_kern_subtable(GdiFont *font,
5862 const struct TT_format0_kern_subtable *tt_f0_ks,
5863 const USHORT *glyph_to_char,
5864 KERNINGPAIR *kern_pair, DWORD cPairs)
5866 USHORT i, nPairs;
5867 const struct TT_kern_pair *tt_kern_pair;
5869 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5871 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5873 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5874 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5875 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5877 if (!kern_pair || !cPairs)
5878 return nPairs;
5880 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5882 nPairs = min(nPairs, cPairs);
5884 for (i = 0; i < nPairs; i++)
5886 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5887 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5888 /* this algorithm appears to better match what Windows does */
5889 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5890 if (kern_pair->iKernAmount < 0)
5892 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5893 kern_pair->iKernAmount -= font->ppem;
5895 else if (kern_pair->iKernAmount > 0)
5897 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5898 kern_pair->iKernAmount += font->ppem;
5900 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5902 TRACE("left %u right %u value %d\n",
5903 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5905 kern_pair++;
5907 TRACE("copied %u entries\n", nPairs);
5908 return nPairs;
5911 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5913 DWORD length;
5914 void *buf;
5915 const struct TT_kern_table *tt_kern_table;
5916 const struct TT_kern_subtable *tt_kern_subtable;
5917 USHORT i, nTables;
5918 USHORT *glyph_to_char;
5920 EnterCriticalSection( &freetype_cs );
5921 if (font->total_kern_pairs != (DWORD)-1)
5923 if (cPairs && kern_pair)
5925 cPairs = min(cPairs, font->total_kern_pairs);
5926 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5927 LeaveCriticalSection( &freetype_cs );
5928 return cPairs;
5930 LeaveCriticalSection( &freetype_cs );
5931 return font->total_kern_pairs;
5934 font->total_kern_pairs = 0;
5936 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5938 if (length == GDI_ERROR)
5940 TRACE("no kerning data in the font\n");
5941 LeaveCriticalSection( &freetype_cs );
5942 return 0;
5945 buf = HeapAlloc(GetProcessHeap(), 0, length);
5946 if (!buf)
5948 WARN("Out of memory\n");
5949 LeaveCriticalSection( &freetype_cs );
5950 return 0;
5953 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5955 /* build a glyph index to char code map */
5956 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5957 if (!glyph_to_char)
5959 WARN("Out of memory allocating a glyph index to char code map\n");
5960 HeapFree(GetProcessHeap(), 0, buf);
5961 LeaveCriticalSection( &freetype_cs );
5962 return 0;
5965 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5967 FT_UInt glyph_code;
5968 FT_ULong char_code;
5970 glyph_code = 0;
5971 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5973 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5974 font->ft_face->num_glyphs, glyph_code, char_code);
5976 while (glyph_code)
5978 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5980 /* FIXME: This doesn't match what Windows does: it does some fancy
5981 * things with duplicate glyph index to char code mappings, while
5982 * we just avoid overriding existing entries.
5984 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5985 glyph_to_char[glyph_code] = (USHORT)char_code;
5987 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5990 else
5992 ULONG n;
5994 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5995 for (n = 0; n <= 65535; n++)
5996 glyph_to_char[n] = (USHORT)n;
5999 tt_kern_table = buf;
6000 nTables = GET_BE_WORD(tt_kern_table->nTables);
6001 TRACE("version %u, nTables %u\n",
6002 GET_BE_WORD(tt_kern_table->version), nTables);
6004 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6006 for (i = 0; i < nTables; i++)
6008 struct TT_kern_subtable tt_kern_subtable_copy;
6010 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6011 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6012 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6014 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6015 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6016 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6018 /* According to the TrueType specification this is the only format
6019 * that will be properly interpreted by Windows and OS/2
6021 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6023 DWORD new_chunk, old_total = font->total_kern_pairs;
6025 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6026 glyph_to_char, NULL, 0);
6027 font->total_kern_pairs += new_chunk;
6029 if (!font->kern_pairs)
6030 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6031 font->total_kern_pairs * sizeof(*font->kern_pairs));
6032 else
6033 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6034 font->total_kern_pairs * sizeof(*font->kern_pairs));
6036 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6037 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6039 else
6040 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6042 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6045 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6046 HeapFree(GetProcessHeap(), 0, buf);
6048 if (cPairs && kern_pair)
6050 cPairs = min(cPairs, font->total_kern_pairs);
6051 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6052 LeaveCriticalSection( &freetype_cs );
6053 return cPairs;
6055 LeaveCriticalSection( &freetype_cs );
6056 return font->total_kern_pairs;
6059 #else /* HAVE_FREETYPE */
6061 /*************************************************************************/
6063 BOOL WineEngInit(void)
6065 return FALSE;
6067 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6069 return NULL;
6071 BOOL WineEngDestroyFontInstance(HFONT hfont)
6073 return FALSE;
6076 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6078 return 1;
6081 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6082 LPWORD pgi, DWORD flags)
6084 return GDI_ERROR;
6087 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6088 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6089 const MAT2* lpmat)
6091 ERR("called but we don't have FreeType\n");
6092 return GDI_ERROR;
6095 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6097 ERR("called but we don't have FreeType\n");
6098 return FALSE;
6101 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6102 OUTLINETEXTMETRICW *potm)
6104 ERR("called but we don't have FreeType\n");
6105 return 0;
6108 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6109 LPINT buffer)
6111 ERR("called but we don't have FreeType\n");
6112 return FALSE;
6115 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6116 LPABC buffer)
6118 ERR("called but we don't have FreeType\n");
6119 return FALSE;
6122 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6123 LPABC buffer)
6125 ERR("called but we don't have FreeType\n");
6126 return FALSE;
6129 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6130 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6132 ERR("called but we don't have FreeType\n");
6133 return FALSE;
6136 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6137 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6139 ERR("called but we don't have FreeType\n");
6140 return FALSE;
6143 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6144 DWORD cbData)
6146 ERR("called but we don't have FreeType\n");
6147 return GDI_ERROR;
6150 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6152 ERR("called but we don't have FreeType\n");
6153 return 0;
6156 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6158 FIXME(":stub\n");
6159 return 1;
6162 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6164 FIXME(":stub\n");
6165 return TRUE;
6168 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6170 FIXME(":stub\n");
6171 return NULL;
6174 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6176 FIXME(":stub\n");
6177 return DEFAULT_CHARSET;
6180 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6182 return FALSE;
6185 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6187 FIXME("(%p, %p): stub\n", font, glyphset);
6188 return 0;
6191 BOOL WineEngFontIsLinked(GdiFont *font)
6193 return FALSE;
6196 /*************************************************************************
6197 * GetRasterizerCaps (GDI32.@)
6199 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6201 lprs->nSize = sizeof(RASTERIZER_STATUS);
6202 lprs->wFlags = 0;
6203 lprs->nLanguageID = 0;
6204 return TRUE;
6207 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6209 ERR("called but we don't have FreeType\n");
6210 return 0;
6213 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6215 ERR("called but we don't have FreeType\n");
6216 return FALSE;
6219 #endif /* HAVE_FREETYPE */