windowscodecs: Add support for converting to 32bppPBGRA.
[wine.git] / dlls / gdi32 / freetype.c
blobb329b3398f553a61203f276f48b3c793ba91b48b
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
94 #ifdef HAVE_FREETYPE
96 #ifdef HAVE_FT2BUILD_H
97 #include <ft2build.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
101 #endif
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
104 #endif
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
110 #endif
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
113 #endif
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
116 #endif
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
119 #endif
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
122 #endif
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
134 #endif
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 typedef enum
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
143 #endif
145 static FT_Library library = 0;
146 typedef struct
148 FT_Int major;
149 FT_Int minor;
150 FT_Int patch;
151 } FT_Version_t;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
170 #else
171 MAKE_FUNCPTR(FT_MulFix);
172 #endif
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
193 #endif
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
208 #endif
210 #undef MAKE_FUNCPTR
212 #ifndef FT_MAKE_TAG
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #endif
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
220 #endif
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
223 #endif
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
226 #endif
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #endif
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
233 #else
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 #endif
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
238 typedef struct {
239 FT_Short height;
240 FT_Short width;
241 FT_Pos size;
242 FT_Pos x_ppem;
243 FT_Pos y_ppem;
244 FT_Short internal_leading;
245 } Bitmap_Size;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
250 typedef struct {
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
253 } My_FT_Bitmap_Size;
255 struct enum_data
257 ENUMLOGFONTEXW elf;
258 NEWTEXTMETRICEXW ntm;
259 DWORD type;
262 typedef struct tagFace {
263 struct list entry;
264 WCHAR *StyleName;
265 char *file;
266 void *font_data_ptr;
267 DWORD font_data_size;
268 FT_Long face_index;
269 FONTSIGNATURE fs;
270 FONTSIGNATURE fs_links;
271 DWORD ntmFlags;
272 FT_Fixed font_version;
273 BOOL scalable;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
279 } Face;
281 typedef struct tagFamily {
282 struct list entry;
283 const WCHAR *FamilyName;
284 struct list faces;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 struct list links;
355 } SYSTEM_LINKS;
357 struct enum_charset_element {
358 DWORD mask;
359 DWORD charset;
360 LPCWSTR name;
363 struct enum_charset_list {
364 DWORD total;
365 struct enum_charset_element element[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
372 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list = LIST_INIT(child_font_list);
375 static struct list system_links = LIST_INIT(system_links);
377 static struct list font_subst_list = LIST_INIT(font_subst_list);
379 static struct list font_list = LIST_INIT(font_list);
381 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
382 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
383 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
385 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
386 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
387 'W','i','n','d','o','w','s','\\',
388 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
389 'F','o','n','t','s','\0'};
391 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
392 'W','i','n','d','o','w','s',' ','N','T','\\',
393 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
394 'F','o','n','t','s','\0'};
396 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
397 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
398 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
399 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
401 static const WCHAR * const SystemFontValues[4] = {
402 System_Value,
403 OEMFont_Value,
404 FixedSys_Value,
405 NULL
408 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
409 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
411 /* Interesting and well-known (frequently-assumed!) font names */
412 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
413 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
414 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
415 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
416 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
417 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
418 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
419 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
421 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
422 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
423 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
424 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
425 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
426 'E','u','r','o','p','e','a','n','\0'};
427 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
428 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
429 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
430 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
431 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
432 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
433 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
434 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
435 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
436 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
437 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
438 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
440 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
441 WesternW, /*00*/
442 Central_EuropeanW,
443 CyrillicW,
444 GreekW,
445 TurkishW,
446 HebrewW,
447 ArabicW,
448 BalticW,
449 VietnameseW, /*08*/
450 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
451 ThaiW,
452 JapaneseW,
453 CHINESE_GB2312W,
454 HangulW,
455 CHINESE_BIG5W,
456 Hangul_Johab_W,
457 NULL, NULL, /*23*/
458 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
459 SymbolW /*31*/
462 typedef struct {
463 WCHAR *name;
464 INT charset;
465 } NameCs;
467 typedef struct tagFontSubst {
468 struct list entry;
469 NameCs from;
470 NameCs to;
471 } FontSubst;
473 struct font_mapping
475 struct list entry;
476 int refcount;
477 dev_t dev;
478 ino_t ino;
479 void *data;
480 size_t size;
483 static struct list mappings_list = LIST_INIT( mappings_list );
485 static CRITICAL_SECTION freetype_cs;
486 static CRITICAL_SECTION_DEBUG critsect_debug =
488 0, 0, &freetype_cs,
489 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
490 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
492 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
494 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
496 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
497 static BOOL use_default_fallback = FALSE;
499 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
501 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
502 'W','i','n','d','o','w','s',' ','N','T','\\',
503 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
504 'S','y','s','t','e','m','L','i','n','k',0};
506 /****************************************
507 * Notes on .fon files
509 * The fonts System, FixedSys and Terminal are special. There are typically multiple
510 * versions installed for different resolutions and codepages. Windows stores which one to use
511 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
512 * Key Meaning
513 * FIXEDFON.FON FixedSys
514 * FONTS.FON System
515 * OEMFONT.FON Terminal
516 * LogPixels Current dpi set by the display control panel applet
517 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
518 * also has a LogPixels value that appears to mirror this)
520 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
521 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
522 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
523 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
524 * so that makes sense.
526 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
527 * to be mapped into the registry on Windows 2000 at least).
528 * I have
529 * woafont=app850.fon
530 * ega80woa.fon=ega80850.fon
531 * ega40woa.fon=ega40850.fon
532 * cga80woa.fon=cga80850.fon
533 * cga40woa.fon=cga40850.fon
536 /* These are all structures needed for the GSUB table */
538 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
539 #define TATEGAKI_LOWER_BOUND 0x02F1
541 typedef struct {
542 DWORD version;
543 WORD ScriptList;
544 WORD FeatureList;
545 WORD LookupList;
546 } GSUB_Header;
548 typedef struct {
549 CHAR ScriptTag[4];
550 WORD Script;
551 } GSUB_ScriptRecord;
553 typedef struct {
554 WORD ScriptCount;
555 GSUB_ScriptRecord ScriptRecord[1];
556 } GSUB_ScriptList;
558 typedef struct {
559 CHAR LangSysTag[4];
560 WORD LangSys;
561 } GSUB_LangSysRecord;
563 typedef struct {
564 WORD DefaultLangSys;
565 WORD LangSysCount;
566 GSUB_LangSysRecord LangSysRecord[1];
567 } GSUB_Script;
569 typedef struct {
570 WORD LookupOrder; /* Reserved */
571 WORD ReqFeatureIndex;
572 WORD FeatureCount;
573 WORD FeatureIndex[1];
574 } GSUB_LangSys;
576 typedef struct {
577 CHAR FeatureTag[4];
578 WORD Feature;
579 } GSUB_FeatureRecord;
581 typedef struct {
582 WORD FeatureCount;
583 GSUB_FeatureRecord FeatureRecord[1];
584 } GSUB_FeatureList;
586 typedef struct {
587 WORD FeatureParams; /* Reserved */
588 WORD LookupCount;
589 WORD LookupListIndex[1];
590 } GSUB_Feature;
592 typedef struct {
593 WORD LookupCount;
594 WORD Lookup[1];
595 } GSUB_LookupList;
597 typedef struct {
598 WORD LookupType;
599 WORD LookupFlag;
600 WORD SubTableCount;
601 WORD SubTable[1];
602 } GSUB_LookupTable;
604 typedef struct {
605 WORD CoverageFormat;
606 WORD GlyphCount;
607 WORD GlyphArray[1];
608 } GSUB_CoverageFormat1;
610 typedef struct {
611 WORD Start;
612 WORD End;
613 WORD StartCoverageIndex;
614 } GSUB_RangeRecord;
616 typedef struct {
617 WORD CoverageFormat;
618 WORD RangeCount;
619 GSUB_RangeRecord RangeRecord[1];
620 } GSUB_CoverageFormat2;
622 typedef struct {
623 WORD SubstFormat; /* = 1 */
624 WORD Coverage;
625 WORD DeltaGlyphID;
626 } GSUB_SingleSubstFormat1;
628 typedef struct {
629 WORD SubstFormat; /* = 2 */
630 WORD Coverage;
631 WORD GlyphCount;
632 WORD Substitute[1];
633 }GSUB_SingleSubstFormat2;
635 #ifdef HAVE_CARBON_CARBON_H
636 static char *find_cache_dir(void)
638 FSRef ref;
639 OSErr err;
640 static char cached_path[MAX_PATH];
641 static const char *wine = "/Wine", *fonts = "/Fonts";
643 if(*cached_path) return cached_path;
645 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
646 if(err != noErr)
648 WARN("can't create cached data folder\n");
649 return NULL;
651 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
652 if(err != noErr)
654 WARN("can't create cached data path\n");
655 *cached_path = '\0';
656 return NULL;
658 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
660 ERR("Could not create full path\n");
661 *cached_path = '\0';
662 return NULL;
664 strcat(cached_path, wine);
666 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
668 WARN("Couldn't mkdir %s\n", cached_path);
669 *cached_path = '\0';
670 return NULL;
672 strcat(cached_path, fonts);
673 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
675 WARN("Couldn't mkdir %s\n", cached_path);
676 *cached_path = '\0';
677 return NULL;
679 return cached_path;
682 /******************************************************************
683 * expand_mac_font
685 * Extracts individual TrueType font files from a Mac suitcase font
686 * and saves them into the user's caches directory (see
687 * find_cache_dir()).
688 * Returns a NULL terminated array of filenames.
690 * We do this because they are apps that try to read ttf files
691 * themselves and they don't like Mac suitcase files.
693 static char **expand_mac_font(const char *path)
695 FSRef ref;
696 SInt16 res_ref;
697 OSStatus s;
698 unsigned int idx;
699 const char *out_dir;
700 const char *filename;
701 int output_len;
702 struct {
703 char **array;
704 unsigned int size, max_size;
705 } ret;
707 TRACE("path %s\n", path);
709 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
710 if(s != noErr)
712 WARN("failed to get ref\n");
713 return NULL;
716 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
717 if(s != noErr)
719 TRACE("no data fork, so trying resource fork\n");
720 res_ref = FSOpenResFile(&ref, fsRdPerm);
721 if(res_ref == -1)
723 TRACE("unable to open resource fork\n");
724 return NULL;
728 ret.size = 0;
729 ret.max_size = 10;
730 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
731 if(!ret.array)
733 CloseResFile(res_ref);
734 return NULL;
737 out_dir = find_cache_dir();
739 filename = strrchr(path, '/');
740 if(!filename) filename = path;
741 else filename++;
743 /* output filename has the form out_dir/filename_%04x.ttf */
744 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
746 UseResFile(res_ref);
747 idx = 1;
748 while(1)
750 FamRec *fam_rec;
751 unsigned short *num_faces_ptr, num_faces, face;
752 AsscEntry *assoc;
753 Handle fond;
754 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
756 fond = Get1IndResource(fond_res, idx);
757 if(!fond) break;
758 TRACE("got fond resource %d\n", idx);
759 HLock(fond);
761 fam_rec = *(FamRec**)fond;
762 num_faces_ptr = (unsigned short *)(fam_rec + 1);
763 num_faces = GET_BE_WORD(*num_faces_ptr);
764 num_faces++;
765 assoc = (AsscEntry*)(num_faces_ptr + 1);
766 TRACE("num faces %04x\n", num_faces);
767 for(face = 0; face < num_faces; face++, assoc++)
769 Handle sfnt;
770 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
771 unsigned short size, font_id;
772 char *output;
774 size = GET_BE_WORD(assoc->fontSize);
775 font_id = GET_BE_WORD(assoc->fontID);
776 if(size != 0)
778 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
779 continue;
782 TRACE("trying to load sfnt id %04x\n", font_id);
783 sfnt = GetResource(sfnt_res, font_id);
784 if(!sfnt)
786 TRACE("can't get sfnt resource %04x\n", font_id);
787 continue;
790 output = HeapAlloc(GetProcessHeap(), 0, output_len);
791 if(output)
793 int fd;
795 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
797 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
798 if(fd != -1 || errno == EEXIST)
800 if(fd != -1)
802 unsigned char *sfnt_data;
804 HLock(sfnt);
805 sfnt_data = *(unsigned char**)sfnt;
806 write(fd, sfnt_data, GetHandleSize(sfnt));
807 HUnlock(sfnt);
808 close(fd);
810 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
812 ret.max_size *= 2;
813 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
815 ret.array[ret.size++] = output;
817 else
819 WARN("unable to create %s\n", output);
820 HeapFree(GetProcessHeap(), 0, output);
823 ReleaseResource(sfnt);
825 HUnlock(fond);
826 ReleaseResource(fond);
827 idx++;
829 CloseResFile(res_ref);
831 return ret.array;
834 #endif /* HAVE_CARBON_CARBON_H */
836 static inline BOOL is_win9x(void)
838 return GetVersion() & 0x80000000;
841 This function builds an FT_Fixed from a double. It fails if the absolute
842 value of the float number is greater than 32768.
844 static inline FT_Fixed FT_FixedFromFloat(double f)
846 return f * 0x10000;
850 This function builds an FT_Fixed from a FIXED. It simply put f.value
851 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
853 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
855 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
859 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
861 Family *family;
862 Face *face;
863 const char *file;
864 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
865 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
867 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
868 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
870 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
872 if(face_name && strcmpiW(face_name, family->FamilyName))
873 continue;
874 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
876 if (!face->file)
877 continue;
878 file = strrchr(face->file, '/');
879 if(!file)
880 file = face->file;
881 else
882 file++;
883 if(!strcasecmp(file, file_nameA))
885 HeapFree(GetProcessHeap(), 0, file_nameA);
886 return face;
890 HeapFree(GetProcessHeap(), 0, file_nameA);
891 return NULL;
894 static Family *find_family_from_name(const WCHAR *name)
896 Family *family;
898 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
900 if(!strcmpiW(family->FamilyName, name))
901 return family;
904 return NULL;
907 static void DumpSubstList(void)
909 FontSubst *psub;
911 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
913 if(psub->from.charset != -1 || psub->to.charset != -1)
914 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
915 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
916 else
917 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
918 debugstr_w(psub->to.name));
920 return;
923 static LPWSTR strdupW(LPCWSTR p)
925 LPWSTR ret;
926 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
927 ret = HeapAlloc(GetProcessHeap(), 0, len);
928 memcpy(ret, p, len);
929 return ret;
932 static LPSTR strdupA(LPCSTR p)
934 LPSTR ret;
935 DWORD len = (strlen(p) + 1);
936 ret = HeapAlloc(GetProcessHeap(), 0, len);
937 memcpy(ret, p, len);
938 return ret;
941 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
942 INT from_charset)
944 FontSubst *element;
946 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
948 if(!strcmpiW(element->from.name, from_name) &&
949 (element->from.charset == from_charset ||
950 element->from.charset == -1))
951 return element;
954 return NULL;
957 #define ADD_FONT_SUBST_FORCE 1
959 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
961 FontSubst *from_exist, *to_exist;
963 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
965 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
967 list_remove(&from_exist->entry);
968 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
969 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
970 HeapFree(GetProcessHeap(), 0, from_exist);
971 from_exist = NULL;
974 if(!from_exist)
976 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
978 if(to_exist)
980 HeapFree(GetProcessHeap(), 0, subst->to.name);
981 subst->to.name = strdupW(to_exist->to.name);
984 list_add_tail(subst_list, &subst->entry);
986 return TRUE;
989 HeapFree(GetProcessHeap(), 0, subst->from.name);
990 HeapFree(GetProcessHeap(), 0, subst->to.name);
991 HeapFree(GetProcessHeap(), 0, subst);
992 return FALSE;
995 static void split_subst_info(NameCs *nc, LPSTR str)
997 CHAR *p = strrchr(str, ',');
998 DWORD len;
1000 nc->charset = -1;
1001 if(p && *(p+1)) {
1002 nc->charset = strtol(p+1, NULL, 10);
1003 *p = '\0';
1005 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1006 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1007 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1010 static void LoadSubstList(void)
1012 FontSubst *psub;
1013 HKEY hkey;
1014 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1015 LPSTR value;
1016 LPVOID data;
1018 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1019 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1020 &hkey) == ERROR_SUCCESS) {
1022 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1023 &valuelen, &datalen, NULL, NULL);
1025 valuelen++; /* returned value doesn't include room for '\0' */
1026 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1027 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1029 dlen = datalen;
1030 vlen = valuelen;
1031 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1032 &dlen) == ERROR_SUCCESS) {
1033 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1035 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1036 split_subst_info(&psub->from, value);
1037 split_subst_info(&psub->to, data);
1039 /* Win 2000 doesn't allow mapping between different charsets
1040 or mapping of DEFAULT_CHARSET */
1041 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1042 psub->to.charset == DEFAULT_CHARSET) {
1043 HeapFree(GetProcessHeap(), 0, psub->to.name);
1044 HeapFree(GetProcessHeap(), 0, psub->from.name);
1045 HeapFree(GetProcessHeap(), 0, psub);
1046 } else {
1047 add_font_subst(&font_subst_list, psub, 0);
1049 /* reset dlen and vlen */
1050 dlen = datalen;
1051 vlen = valuelen;
1053 HeapFree(GetProcessHeap(), 0, data);
1054 HeapFree(GetProcessHeap(), 0, value);
1055 RegCloseKey(hkey);
1060 /*****************************************************************
1061 * get_name_table_entry
1063 * Supply the platform, encoding, language and name ids in req
1064 * and if the name exists the function will fill in the string
1065 * and string_len members. The string is owned by FreeType so
1066 * don't free it. Returns TRUE if the name is found else FALSE.
1068 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1070 FT_SfntName name;
1071 FT_UInt num_names, name_index;
1073 if(FT_IS_SFNT(ft_face))
1075 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1077 for(name_index = 0; name_index < num_names; name_index++)
1079 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1081 if((name.platform_id == req->platform_id) &&
1082 (name.encoding_id == req->encoding_id) &&
1083 (name.language_id == req->language_id) &&
1084 (name.name_id == req->name_id))
1086 req->string = name.string;
1087 req->string_len = name.string_len;
1088 return TRUE;
1093 req->string = NULL;
1094 req->string_len = 0;
1095 return FALSE;
1098 static WCHAR *get_familyname(FT_Face ft_face)
1100 WCHAR *family = NULL;
1101 FT_SfntName name;
1103 name.platform_id = TT_PLATFORM_MICROSOFT;
1104 name.encoding_id = TT_MS_ID_UNICODE_CS;
1105 name.language_id = GetUserDefaultLCID();
1106 name.name_id = TT_NAME_ID_FONT_FAMILY;
1108 if(get_name_table_entry(ft_face, &name))
1110 FT_UInt i;
1112 /* String is not nul terminated and string_len is a byte length. */
1113 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1114 for(i = 0; i < name.string_len / 2; i++)
1116 WORD *tmp = (WORD *)&name.string[i * 2];
1117 family[i] = GET_BE_WORD(*tmp);
1119 family[i] = 0;
1120 TRACE("Got localised name %s\n", debugstr_w(family));
1123 return family;
1127 /*****************************************************************
1128 * load_sfnt_table
1130 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1131 * of FreeType that don't export this function.
1134 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1137 FT_Error err;
1139 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1140 if(pFT_Load_Sfnt_Table)
1142 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1144 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1145 else /* Do it the hard way */
1147 TT_Face tt_face = (TT_Face) ft_face;
1148 SFNT_Interface *sfnt;
1149 if (FT_Version.major==2 && FT_Version.minor==0)
1151 /* 2.0.x */
1152 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1154 else
1156 /* A field was added in the middle of the structure in 2.1.x */
1157 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1159 err = sfnt->load_any(tt_face, table, offset, buf, len);
1161 #else
1162 else
1164 static int msg;
1165 if(!msg)
1167 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1168 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1169 "Please upgrade your freetype library.\n");
1170 msg++;
1172 err = FT_Err_Unimplemented_Feature;
1174 #endif
1175 return err;
1178 static inline int TestStyles(DWORD flags, DWORD styles)
1180 return (flags & styles) == styles;
1183 static int StyleOrdering(Face *face)
1185 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1186 return 3;
1187 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1188 return 2;
1189 if (TestStyles(face->ntmFlags, NTM_BOLD))
1190 return 1;
1191 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1192 return 0;
1194 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1195 debugstr_w(face->family->FamilyName),
1196 debugstr_w(face->StyleName),
1197 face->ntmFlags);
1199 return 9999;
1202 /* Add a style of face to a font family using an ordering of the list such
1203 that regular fonts come before bold and italic, and single styles come
1204 before compound styles. */
1205 static void AddFaceToFamily(Face *face, Family *family)
1207 struct list *entry;
1209 LIST_FOR_EACH( entry, &family->faces )
1211 Face *ent = LIST_ENTRY(entry, Face, entry);
1212 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1214 list_add_before( entry, &face->entry );
1217 #define ADDFONT_EXTERNAL_FONT 0x01
1218 #define ADDFONT_FORCE_BITMAP 0x02
1219 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1221 FT_Face ft_face;
1222 TT_OS2 *pOS2;
1223 TT_Header *pHeader = NULL;
1224 WCHAR *english_family, *localised_family, *StyleW;
1225 DWORD len;
1226 Family *family;
1227 Face *face;
1228 struct list *family_elem_ptr, *face_elem_ptr;
1229 FT_Error err;
1230 FT_Long face_index = 0, num_faces;
1231 #ifdef HAVE_FREETYPE_FTWINFNT_H
1232 FT_WinFNT_HeaderRec winfnt_header;
1233 #endif
1234 int i, bitmap_num, internal_leading;
1235 FONTSIGNATURE fs;
1237 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1238 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1240 #ifdef HAVE_CARBON_CARBON_H
1241 if(file && !fake_family)
1243 char **mac_list = expand_mac_font(file);
1244 if(mac_list)
1246 BOOL had_one = FALSE;
1247 char **cursor;
1248 for(cursor = mac_list; *cursor; cursor++)
1250 had_one = TRUE;
1251 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1252 HeapFree(GetProcessHeap(), 0, *cursor);
1254 HeapFree(GetProcessHeap(), 0, mac_list);
1255 if(had_one)
1256 return 1;
1259 #endif /* HAVE_CARBON_CARBON_H */
1261 do {
1262 char *family_name = fake_family;
1264 if (file)
1266 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1267 err = pFT_New_Face(library, file, face_index, &ft_face);
1268 } else
1270 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1271 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1274 if(err != 0) {
1275 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1276 return 0;
1279 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*/
1280 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1281 pFT_Done_Face(ft_face);
1282 return 0;
1285 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1286 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1287 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1288 pFT_Done_Face(ft_face);
1289 return 0;
1292 if(FT_IS_SFNT(ft_face))
1294 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1295 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1296 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1298 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1299 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1300 pFT_Done_Face(ft_face);
1301 return 0;
1304 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1305 we don't want to load these. */
1306 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1308 FT_ULong len = 0;
1310 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1312 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1313 pFT_Done_Face(ft_face);
1314 return 0;
1319 if(!ft_face->family_name || !ft_face->style_name) {
1320 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1321 pFT_Done_Face(ft_face);
1322 return 0;
1325 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1327 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1328 pFT_Done_Face(ft_face);
1329 return 0;
1332 if (target_family)
1334 localised_family = get_familyname(ft_face);
1335 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1337 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1338 HeapFree(GetProcessHeap(), 0, localised_family);
1339 num_faces = ft_face->num_faces;
1340 pFT_Done_Face(ft_face);
1341 continue;
1343 HeapFree(GetProcessHeap(), 0, localised_family);
1346 if(!family_name)
1347 family_name = ft_face->family_name;
1349 bitmap_num = 0;
1350 do {
1351 My_FT_Bitmap_Size *size = NULL;
1352 FT_ULong tmp_size;
1354 if(!FT_IS_SCALABLE(ft_face))
1355 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1357 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1358 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1359 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1361 localised_family = NULL;
1362 if(!fake_family) {
1363 localised_family = get_familyname(ft_face);
1364 if(localised_family && !strcmpiW(localised_family, english_family)) {
1365 HeapFree(GetProcessHeap(), 0, localised_family);
1366 localised_family = NULL;
1370 family = NULL;
1371 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1372 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1373 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1374 break;
1375 family = NULL;
1377 if(!family) {
1378 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1379 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1380 list_init(&family->faces);
1381 list_add_tail(&font_list, &family->entry);
1383 if(localised_family) {
1384 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1385 subst->from.name = strdupW(english_family);
1386 subst->from.charset = -1;
1387 subst->to.name = strdupW(localised_family);
1388 subst->to.charset = -1;
1389 add_font_subst(&font_subst_list, subst, 0);
1392 HeapFree(GetProcessHeap(), 0, localised_family);
1393 HeapFree(GetProcessHeap(), 0, english_family);
1395 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1396 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1397 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1399 internal_leading = 0;
1400 memset(&fs, 0, sizeof(fs));
1402 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1403 if(pOS2) {
1404 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1405 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1406 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1407 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1408 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1409 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1410 if(pOS2->version == 0) {
1411 FT_UInt dummy;
1413 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1414 fs.fsCsb[0] |= FS_LATIN1;
1415 else
1416 fs.fsCsb[0] |= FS_SYMBOL;
1419 #ifdef HAVE_FREETYPE_FTWINFNT_H
1420 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1421 CHARSETINFO csi;
1422 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1423 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1424 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1425 fs = csi.fs;
1426 internal_leading = winfnt_header.internal_leading;
1428 #endif
1430 face_elem_ptr = list_head(&family->faces);
1431 while(face_elem_ptr) {
1432 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1433 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1434 if(!strcmpiW(face->StyleName, StyleW) &&
1435 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1436 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1437 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1438 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1440 if(fake_family) {
1441 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1442 HeapFree(GetProcessHeap(), 0, StyleW);
1443 pFT_Done_Face(ft_face);
1444 return 1;
1446 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1447 TRACE("Original font is newer so skipping this one\n");
1448 HeapFree(GetProcessHeap(), 0, StyleW);
1449 pFT_Done_Face(ft_face);
1450 return 1;
1451 } else {
1452 TRACE("Replacing original with this one\n");
1453 list_remove(&face->entry);
1454 HeapFree(GetProcessHeap(), 0, face->file);
1455 HeapFree(GetProcessHeap(), 0, face->StyleName);
1456 HeapFree(GetProcessHeap(), 0, face);
1457 break;
1461 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1462 face->cached_enum_data = NULL;
1463 face->StyleName = StyleW;
1464 if (file)
1466 face->file = strdupA(file);
1467 face->font_data_ptr = NULL;
1468 face->font_data_size = 0;
1470 else
1472 face->file = NULL;
1473 face->font_data_ptr = font_data_ptr;
1474 face->font_data_size = font_data_size;
1476 face->face_index = face_index;
1477 face->ntmFlags = 0;
1478 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1479 face->ntmFlags |= NTM_ITALIC;
1480 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1481 face->ntmFlags |= NTM_BOLD;
1482 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1483 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1484 face->family = family;
1485 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1486 face->fs = fs;
1487 memset(&face->fs_links, 0, sizeof(face->fs_links));
1489 if(FT_IS_SCALABLE(ft_face)) {
1490 memset(&face->size, 0, sizeof(face->size));
1491 face->scalable = TRUE;
1492 } else {
1493 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1494 size->height, size->width, size->size >> 6,
1495 size->x_ppem >> 6, size->y_ppem >> 6);
1496 face->size.height = size->height;
1497 face->size.width = size->width;
1498 face->size.size = size->size;
1499 face->size.x_ppem = size->x_ppem;
1500 face->size.y_ppem = size->y_ppem;
1501 face->size.internal_leading = internal_leading;
1502 face->scalable = FALSE;
1505 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1506 tmp_size = 0;
1507 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1509 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1510 face->ntmFlags |= NTM_PS_OPENTYPE;
1513 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1514 face->fs.fsCsb[0], face->fs.fsCsb[1],
1515 face->fs.fsUsb[0], face->fs.fsUsb[1],
1516 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1519 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1520 for(i = 0; i < ft_face->num_charmaps; i++) {
1521 switch(ft_face->charmaps[i]->encoding) {
1522 case FT_ENCODING_UNICODE:
1523 case FT_ENCODING_APPLE_ROMAN:
1524 face->fs.fsCsb[0] |= FS_LATIN1;
1525 break;
1526 case FT_ENCODING_MS_SYMBOL:
1527 face->fs.fsCsb[0] |= FS_SYMBOL;
1528 break;
1529 default:
1530 break;
1535 AddFaceToFamily(face, family);
1537 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1539 num_faces = ft_face->num_faces;
1540 pFT_Done_Face(ft_face);
1541 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1542 debugstr_w(StyleW));
1543 } while(num_faces > ++face_index);
1544 return num_faces;
1547 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1549 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1552 static void DumpFontList(void)
1554 Family *family;
1555 Face *face;
1556 struct list *family_elem_ptr, *face_elem_ptr;
1558 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1559 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1560 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1561 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1562 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1563 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1564 if(!face->scalable)
1565 TRACE(" %d", face->size.height);
1566 TRACE("\n");
1569 return;
1572 /***********************************************************
1573 * The replacement list is a way to map an entire font
1574 * family onto another family. For example adding
1576 * [HKCU\Software\Wine\Fonts\Replacements]
1577 * "Wingdings"="Winedings"
1579 * would enumerate the Winedings font both as Winedings and
1580 * Wingdings. However if a real Wingdings font is present the
1581 * replacement does not take place.
1584 static void LoadReplaceList(void)
1586 HKEY hkey;
1587 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1588 LPWSTR value;
1589 LPVOID data;
1590 Family *family;
1591 Face *face;
1592 struct list *family_elem_ptr, *face_elem_ptr;
1593 CHAR familyA[400];
1595 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1596 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1598 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1599 &valuelen, &datalen, NULL, NULL);
1601 valuelen++; /* returned value doesn't include room for '\0' */
1602 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1603 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1605 dlen = datalen;
1606 vlen = valuelen;
1607 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1608 &dlen) == ERROR_SUCCESS) {
1609 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1610 /* "NewName"="Oldname" */
1611 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1613 /* Find the old family and hence all of the font files
1614 in that family */
1615 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1616 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1617 if(!strcmpiW(family->FamilyName, data)) {
1618 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1619 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1620 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1621 debugstr_w(face->StyleName), familyA);
1622 /* Now add a new entry with the new family name */
1623 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1625 break;
1628 /* reset dlen and vlen */
1629 dlen = datalen;
1630 vlen = valuelen;
1632 HeapFree(GetProcessHeap(), 0, data);
1633 HeapFree(GetProcessHeap(), 0, value);
1634 RegCloseKey(hkey);
1638 /*************************************************************
1639 * init_system_links
1641 static BOOL init_system_links(void)
1643 HKEY hkey;
1644 BOOL ret = FALSE;
1645 DWORD type, max_val, max_data, val_len, data_len, index;
1646 WCHAR *value, *data;
1647 WCHAR *entry, *next;
1648 SYSTEM_LINKS *font_link, *system_font_link;
1649 CHILD_FONT *child_font;
1650 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1651 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1652 FONTSIGNATURE fs;
1653 Family *family;
1654 Face *face;
1655 FontSubst *psub;
1657 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1659 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1660 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1661 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1662 val_len = max_val + 1;
1663 data_len = max_data;
1664 index = 0;
1665 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1667 memset(&fs, 0, sizeof(fs));
1668 psub = get_font_subst(&font_subst_list, value, -1);
1669 /* Don't store fonts that are only substitutes for other fonts */
1670 if(psub)
1672 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1673 goto next;
1675 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1676 font_link->font_name = strdupW(value);
1677 list_init(&font_link->links);
1678 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1680 WCHAR *face_name;
1681 CHILD_FONT *child_font;
1683 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1685 next = entry + strlenW(entry) + 1;
1687 face_name = strchrW(entry, ',');
1688 if(face_name)
1690 *face_name++ = 0;
1691 while(isspaceW(*face_name))
1692 face_name++;
1694 psub = get_font_subst(&font_subst_list, face_name, -1);
1695 if(psub)
1696 face_name = psub->to.name;
1698 face = find_face_from_filename(entry, face_name);
1699 if(!face)
1701 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1702 continue;
1705 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1706 child_font->face = face;
1707 child_font->font = NULL;
1708 fs.fsCsb[0] |= face->fs.fsCsb[0];
1709 fs.fsCsb[1] |= face->fs.fsCsb[1];
1710 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1711 list_add_tail(&font_link->links, &child_font->entry);
1713 family = find_family_from_name(font_link->font_name);
1714 if(family)
1716 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1718 face->fs_links = fs;
1721 list_add_tail(&system_links, &font_link->entry);
1722 next:
1723 val_len = max_val + 1;
1724 data_len = max_data;
1727 HeapFree(GetProcessHeap(), 0, value);
1728 HeapFree(GetProcessHeap(), 0, data);
1729 RegCloseKey(hkey);
1732 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1733 that Tahoma has */
1735 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1736 system_font_link->font_name = strdupW(System);
1737 list_init(&system_font_link->links);
1739 face = find_face_from_filename(tahoma_ttf, Tahoma);
1740 if(face)
1742 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1743 child_font->face = face;
1744 child_font->font = NULL;
1745 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1746 list_add_tail(&system_font_link->links, &child_font->entry);
1748 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1750 if(!strcmpiW(font_link->font_name, Tahoma))
1752 CHILD_FONT *font_link_entry;
1753 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1755 CHILD_FONT *new_child;
1756 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1757 new_child->face = font_link_entry->face;
1758 new_child->font = NULL;
1759 list_add_tail(&system_font_link->links, &new_child->entry);
1761 break;
1764 list_add_tail(&system_links, &system_font_link->entry);
1765 return ret;
1768 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1770 DIR *dir;
1771 struct dirent *dent;
1772 char path[MAX_PATH];
1774 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1776 dir = opendir(dirname);
1777 if(!dir) {
1778 WARN("Can't open directory %s\n", debugstr_a(dirname));
1779 return FALSE;
1781 while((dent = readdir(dir)) != NULL) {
1782 struct stat statbuf;
1784 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1785 continue;
1787 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1789 sprintf(path, "%s/%s", dirname, dent->d_name);
1791 if(stat(path, &statbuf) == -1)
1793 WARN("Can't stat %s\n", debugstr_a(path));
1794 continue;
1796 if(S_ISDIR(statbuf.st_mode))
1797 ReadFontDir(path, external_fonts);
1798 else
1799 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1801 closedir(dir);
1802 return TRUE;
1805 static void load_fontconfig_fonts(void)
1807 #ifdef SONAME_LIBFONTCONFIG
1808 void *fc_handle = NULL;
1809 FcConfig *config;
1810 FcPattern *pat;
1811 FcObjectSet *os;
1812 FcFontSet *fontset;
1813 int i, len;
1814 char *file;
1815 const char *ext;
1817 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1818 if(!fc_handle) {
1819 TRACE("Wine cannot find the fontconfig library (%s).\n",
1820 SONAME_LIBFONTCONFIG);
1821 return;
1823 #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;}
1824 LOAD_FUNCPTR(FcConfigGetCurrent);
1825 LOAD_FUNCPTR(FcFontList);
1826 LOAD_FUNCPTR(FcFontSetDestroy);
1827 LOAD_FUNCPTR(FcInit);
1828 LOAD_FUNCPTR(FcObjectSetAdd);
1829 LOAD_FUNCPTR(FcObjectSetCreate);
1830 LOAD_FUNCPTR(FcObjectSetDestroy);
1831 LOAD_FUNCPTR(FcPatternCreate);
1832 LOAD_FUNCPTR(FcPatternDestroy);
1833 LOAD_FUNCPTR(FcPatternGetBool);
1834 LOAD_FUNCPTR(FcPatternGetString);
1835 #undef LOAD_FUNCPTR
1837 if(!pFcInit()) return;
1839 config = pFcConfigGetCurrent();
1840 pat = pFcPatternCreate();
1841 os = pFcObjectSetCreate();
1842 pFcObjectSetAdd(os, FC_FILE);
1843 pFcObjectSetAdd(os, FC_SCALABLE);
1844 fontset = pFcFontList(config, pat, os);
1845 if(!fontset) return;
1846 for(i = 0; i < fontset->nfont; i++) {
1847 FcBool scalable;
1849 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1850 continue;
1851 TRACE("fontconfig: %s\n", file);
1853 /* We're just interested in OT/TT fonts for now, so this hack just
1854 picks up the scalable fonts without extensions .pf[ab] to save time
1855 loading every other font */
1857 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1859 TRACE("not scalable\n");
1860 continue;
1863 len = strlen( file );
1864 if(len < 4) continue;
1865 ext = &file[ len - 3 ];
1866 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1867 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1869 pFcFontSetDestroy(fontset);
1870 pFcObjectSetDestroy(os);
1871 pFcPatternDestroy(pat);
1872 sym_not_found:
1873 #endif
1874 return;
1877 static BOOL load_font_from_data_dir(LPCWSTR file)
1879 BOOL ret = FALSE;
1880 const char *data_dir = wine_get_data_dir();
1882 if (!data_dir) data_dir = wine_get_build_dir();
1884 if (data_dir)
1886 INT len;
1887 char *unix_name;
1889 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1891 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1893 strcpy(unix_name, data_dir);
1894 strcat(unix_name, "/fonts/");
1896 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1898 EnterCriticalSection( &freetype_cs );
1899 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1900 LeaveCriticalSection( &freetype_cs );
1901 HeapFree(GetProcessHeap(), 0, unix_name);
1903 return ret;
1906 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1908 static const WCHAR slashW[] = {'\\','\0'};
1909 BOOL ret = FALSE;
1910 WCHAR windowsdir[MAX_PATH];
1911 char *unixname;
1913 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1914 strcatW(windowsdir, fontsW);
1915 strcatW(windowsdir, slashW);
1916 strcatW(windowsdir, file);
1917 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1918 EnterCriticalSection( &freetype_cs );
1919 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1920 LeaveCriticalSection( &freetype_cs );
1921 HeapFree(GetProcessHeap(), 0, unixname);
1923 return ret;
1926 static void load_system_fonts(void)
1928 HKEY hkey;
1929 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1930 const WCHAR * const *value;
1931 DWORD dlen, type;
1932 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1933 char *unixname;
1935 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1936 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1937 strcatW(windowsdir, fontsW);
1938 for(value = SystemFontValues; *value; value++) {
1939 dlen = sizeof(data);
1940 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1941 type == REG_SZ) {
1942 BOOL added = FALSE;
1944 sprintfW(pathW, fmtW, windowsdir, data);
1945 if((unixname = wine_get_unix_file_name(pathW))) {
1946 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1947 HeapFree(GetProcessHeap(), 0, unixname);
1949 if (!added)
1950 load_font_from_data_dir(data);
1953 RegCloseKey(hkey);
1957 /*************************************************************
1959 * This adds registry entries for any externally loaded fonts
1960 * (fonts from fontconfig or FontDirs). It also deletes entries
1961 * of no longer existing fonts.
1964 static void update_reg_entries(void)
1966 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1967 LPWSTR valueW;
1968 DWORD len, len_fam;
1969 Family *family;
1970 Face *face;
1971 struct list *family_elem_ptr, *face_elem_ptr;
1972 WCHAR *file;
1973 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1974 static const WCHAR spaceW[] = {' ', '\0'};
1975 char *path;
1977 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1978 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1979 ERR("Can't create Windows font reg key\n");
1980 goto end;
1983 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1984 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1985 ERR("Can't create Windows font reg key\n");
1986 goto end;
1989 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1990 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1991 ERR("Can't create external font reg key\n");
1992 goto end;
1995 /* enumerate the fonts and add external ones to the two keys */
1997 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1998 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1999 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2000 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2001 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2002 if(!face->external) continue;
2003 len = len_fam;
2004 if (!(face->ntmFlags & NTM_REGULAR))
2005 len = len_fam + strlenW(face->StyleName) + 1;
2006 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2007 strcpyW(valueW, family->FamilyName);
2008 if(len != len_fam) {
2009 strcatW(valueW, spaceW);
2010 strcatW(valueW, face->StyleName);
2012 strcatW(valueW, TrueType);
2014 file = wine_get_dos_file_name(face->file);
2015 if(file)
2016 len = strlenW(file) + 1;
2017 else
2019 if((path = strrchr(face->file, '/')) == NULL)
2020 path = face->file;
2021 else
2022 path++;
2023 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2025 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2026 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2028 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2029 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2030 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2032 HeapFree(GetProcessHeap(), 0, file);
2033 HeapFree(GetProcessHeap(), 0, valueW);
2036 end:
2037 if(external_key) RegCloseKey(external_key);
2038 if(win9x_key) RegCloseKey(win9x_key);
2039 if(winnt_key) RegCloseKey(winnt_key);
2040 return;
2043 static void delete_external_font_keys(void)
2045 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2046 DWORD dlen, vlen, datalen, valuelen, i, type;
2047 LPWSTR valueW;
2048 LPVOID data;
2050 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2051 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2052 ERR("Can't create Windows font reg key\n");
2053 goto end;
2056 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2057 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2058 ERR("Can't create Windows font reg key\n");
2059 goto end;
2062 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2063 ERR("Can't create external font reg key\n");
2064 goto end;
2067 /* Delete all external fonts added last time */
2069 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2070 &valuelen, &datalen, NULL, NULL);
2071 valuelen++; /* returned value doesn't include room for '\0' */
2072 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2073 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2075 dlen = datalen * sizeof(WCHAR);
2076 vlen = valuelen;
2077 i = 0;
2078 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2079 &dlen) == ERROR_SUCCESS) {
2081 RegDeleteValueW(winnt_key, valueW);
2082 RegDeleteValueW(win9x_key, valueW);
2083 /* reset dlen and vlen */
2084 dlen = datalen;
2085 vlen = valuelen;
2087 HeapFree(GetProcessHeap(), 0, data);
2088 HeapFree(GetProcessHeap(), 0, valueW);
2090 /* Delete the old external fonts key */
2091 RegCloseKey(external_key);
2092 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2094 end:
2095 if(win9x_key) RegCloseKey(win9x_key);
2096 if(winnt_key) RegCloseKey(winnt_key);
2099 /*************************************************************
2100 * WineEngAddFontResourceEx
2103 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2105 INT ret = 0;
2107 GDI_CheckNotLock();
2109 if (ft_handle) /* do it only if we have freetype up and running */
2111 char *unixname;
2113 if(flags)
2114 FIXME("Ignoring flags %x\n", flags);
2116 if((unixname = wine_get_unix_file_name(file)))
2118 EnterCriticalSection( &freetype_cs );
2119 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2120 LeaveCriticalSection( &freetype_cs );
2121 HeapFree(GetProcessHeap(), 0, unixname);
2123 if (!ret && !strchrW(file, '\\')) {
2124 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2125 ret = load_font_from_winfonts_dir(file);
2126 if (!ret) {
2127 /* Try in datadir/fonts (or builddir/fonts),
2128 * needed for Magic the Gathering Online
2130 ret = load_font_from_data_dir(file);
2134 return ret;
2137 /*************************************************************
2138 * WineEngAddFontMemResourceEx
2141 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2143 GDI_CheckNotLock();
2145 if (ft_handle) /* do it only if we have freetype up and running */
2147 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2149 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2150 memcpy(pFontCopy, pbFont, cbFont);
2152 EnterCriticalSection( &freetype_cs );
2153 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2154 LeaveCriticalSection( &freetype_cs );
2156 if (*pcFonts == 0)
2158 TRACE("AddFontToList failed\n");
2159 HeapFree(GetProcessHeap(), 0, pFontCopy);
2160 return 0;
2162 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2163 * For now return something unique but quite random
2165 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2166 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2169 *pcFonts = 0;
2170 return 0;
2173 /*************************************************************
2174 * WineEngRemoveFontResourceEx
2177 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2179 GDI_CheckNotLock();
2180 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2181 return TRUE;
2184 static const struct nls_update_font_list
2186 UINT ansi_cp, oem_cp;
2187 const char *oem, *fixed, *system;
2188 const char *courier, *serif, *small, *sserif;
2189 /* these are for font substitutes */
2190 const char *shelldlg, *tmsrmn;
2191 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2192 *helv_0, *tmsrmn_0;
2193 const struct subst
2195 const char *from, *to;
2196 } arial_0, courier_new_0, times_new_roman_0;
2197 } nls_update_font_list[] =
2199 /* Latin 1 (United States) */
2200 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "Tahoma","Times New Roman",
2203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2204 { 0 }, { 0 }, { 0 }
2206 /* Latin 1 (Multilingual) */
2207 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2208 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2211 { 0 }, { 0 }, { 0 }
2213 /* Eastern Europe */
2214 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2215 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,238", "System,238",
2218 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2219 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2220 { "Arial CE,0", "Arial,238" },
2221 { "Courier New CE,0", "Courier New,238" },
2222 { "Times New Roman CE,0", "Times New Roman,238" }
2224 /* Cyrillic */
2225 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2226 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,204", "System,204",
2229 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2230 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2231 { "Arial Cyr,0", "Arial,204" },
2232 { "Courier New Cyr,0", "Courier New,204" },
2233 { "Times New Roman Cyr,0", "Times New Roman,204" }
2235 /* Greek */
2236 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2237 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,161", "System,161",
2240 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2241 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2242 { "Arial Greek,0", "Arial,161" },
2243 { "Courier New Greek,0", "Courier New,161" },
2244 { "Times New Roman Greek,0", "Times New Roman,161" }
2246 /* Turkish */
2247 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2248 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2249 "Tahoma","Times New Roman", /* FIXME unverified */
2250 "Fixedsys,162", "System,162",
2251 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2252 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2253 { "Arial Tur,0", "Arial,162" },
2254 { "Courier New Tur,0", "Courier New,162" },
2255 { "Times New Roman Tur,0", "Times New Roman,162" }
2257 /* Hebrew */
2258 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2259 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2260 "Tahoma","Times New Roman", /* FIXME unverified */
2261 "Fixedsys,177", "System,177",
2262 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2263 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2264 { 0 }, { 0 }, { 0 }
2266 /* Arabic */
2267 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2268 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2269 "Tahoma","Times New Roman", /* FIXME unverified */
2270 "Fixedsys,178", "System,178",
2271 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2272 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2273 { 0 }, { 0 }, { 0 }
2275 /* Baltic */
2276 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2277 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 "Fixedsys,186", "System,186",
2280 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2281 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2282 { "Arial Baltic,0", "Arial,186" },
2283 { "Courier New Baltic,0", "Courier New,186" },
2284 { "Times New Roman Baltic,0", "Times New Roman,186" }
2286 /* Vietnamese */
2287 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2288 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2289 "Tahoma","Times New Roman", /* FIXME unverified */
2290 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2291 { 0 }, { 0 }, { 0 }
2293 /* Thai */
2294 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2295 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2296 "Tahoma","Times New Roman", /* FIXME unverified */
2297 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2298 { 0 }, { 0 }, { 0 }
2300 /* Japanese */
2301 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2302 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2303 "MS UI Gothic","MS Serif",
2304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2305 { 0 }, { 0 }, { 0 }
2307 /* Chinese Simplified */
2308 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2309 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2310 "SimSun", "NSimSun",
2311 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2312 { 0 }, { 0 }, { 0 }
2314 /* Korean */
2315 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2316 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2317 "Gulim", "Batang",
2318 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2319 { 0 }, { 0 }, { 0 }
2321 /* Chinese Traditional */
2322 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2323 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2324 "PMingLiU", "MingLiU",
2325 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2326 { 0 }, { 0 }, { 0 }
2330 static const WCHAR *font_links_list[] =
2332 Lucida_Sans_Unicode,
2333 Microsoft_Sans_Serif,
2334 Tahoma
2337 static const struct font_links_defaults_list
2339 /* Keyed off substitution for "MS Shell Dlg" */
2340 const WCHAR *shelldlg;
2341 /* Maximum of four substitutes, plus terminating NULL pointer */
2342 const WCHAR *substitutes[5];
2343 } font_links_defaults_list[] =
2345 /* Non East-Asian */
2346 { Tahoma, /* FIXME unverified ordering */
2347 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2349 /* Below lists are courtesy of
2350 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2352 /* Japanese */
2353 { MS_UI_Gothic,
2354 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2356 /* Chinese Simplified */
2357 { SimSun,
2358 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2360 /* Korean */
2361 { Gulim,
2362 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2364 /* Chinese Traditional */
2365 { PMingLiU,
2366 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2370 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2372 return ( ansi_cp == 932 /* CP932 for Japanese */
2373 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2374 || ansi_cp == 949 /* CP949 for Korean */
2375 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2378 static inline HKEY create_fonts_NT_registry_key(void)
2380 HKEY hkey = 0;
2382 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2383 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2384 return hkey;
2387 static inline HKEY create_fonts_9x_registry_key(void)
2389 HKEY hkey = 0;
2391 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2392 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2393 return hkey;
2396 static inline HKEY create_config_fonts_registry_key(void)
2398 HKEY hkey = 0;
2400 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2401 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2402 return hkey;
2405 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2407 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2408 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2409 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2410 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2413 static void set_value_key(HKEY hkey, const char *name, const char *value)
2415 if (value)
2416 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2417 else if (name)
2418 RegDeleteValueA(hkey, name);
2421 static void update_font_info(void)
2423 char buf[40], cpbuf[40];
2424 DWORD len, type;
2425 HKEY hkey = 0;
2426 UINT i, ansi_cp = 0, oem_cp = 0;
2427 BOOL done = FALSE;
2429 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2430 return;
2432 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2433 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2434 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2435 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2436 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2438 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2439 if (is_dbcs_ansi_cp(ansi_cp))
2440 use_default_fallback = TRUE;
2442 len = sizeof(buf);
2443 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2445 if (!strcmp( buf, cpbuf )) /* already set correctly */
2447 RegCloseKey(hkey);
2448 return;
2450 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2452 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2454 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2455 RegCloseKey(hkey);
2457 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2459 HKEY hkey;
2461 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2462 nls_update_font_list[i].oem_cp == oem_cp)
2464 hkey = create_config_fonts_registry_key();
2465 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2466 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2467 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2468 RegCloseKey(hkey);
2470 hkey = create_fonts_NT_registry_key();
2471 add_font_list(hkey, &nls_update_font_list[i]);
2472 RegCloseKey(hkey);
2474 hkey = create_fonts_9x_registry_key();
2475 add_font_list(hkey, &nls_update_font_list[i]);
2476 RegCloseKey(hkey);
2478 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2480 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2481 strlen(nls_update_font_list[i].shelldlg)+1);
2482 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2483 strlen(nls_update_font_list[i].tmsrmn)+1);
2485 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2486 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2487 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2488 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2489 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2490 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2491 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2492 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2494 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2495 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2496 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2498 RegCloseKey(hkey);
2500 done = TRUE;
2502 else
2504 /* Delete the FontSubstitutes from other locales */
2505 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2507 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2508 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2509 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2510 RegCloseKey(hkey);
2514 if (!done)
2515 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2517 /* Clear out system links */
2518 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2521 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2523 const WCHAR *value;
2524 int i;
2525 FontSubst *psub;
2526 Family *family;
2527 Face *face;
2528 const char *file;
2529 WCHAR *fileW;
2530 int fileLen;
2531 WCHAR buff[MAX_PATH];
2532 WCHAR *data;
2533 int entryLen;
2535 static const WCHAR comma[] = {',',0};
2537 RegDeleteValueW(hkey, name);
2538 if (values)
2540 data = buff;
2541 data[0] = '\0';
2542 for (i = 0; values[i] != NULL; i++)
2544 value = values[i];
2545 if (!strcmpiW(name,value))
2546 continue;
2547 psub = get_font_subst(&font_subst_list, value, -1);
2548 if(psub)
2549 value = psub->to.name;
2550 family = find_family_from_name(value);
2551 if (!family)
2552 continue;
2553 file = NULL;
2554 /* Use first extant filename for this Family */
2555 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2557 if (!face->file)
2558 continue;
2559 file = strrchr(face->file, '/');
2560 if (!file)
2561 file = face->file;
2562 else
2563 file++;
2564 break;
2566 if (!file)
2567 continue;
2568 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2569 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2570 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2571 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2572 if (sizeof(buff)-(data-buff) < entryLen + 1)
2574 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2575 HeapFree(GetProcessHeap(), 0, fileW);
2576 break;
2578 strcpyW(data, fileW);
2579 strcatW(data, comma);
2580 strcatW(data, value);
2581 data += entryLen;
2582 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2583 HeapFree(GetProcessHeap(), 0, fileW);
2585 if (data != buff)
2587 *data='\0';
2588 data++;
2589 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2590 } else
2591 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2592 } else
2593 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2596 static void update_system_links(void)
2598 HKEY hkey = 0;
2599 UINT i, j;
2600 BOOL done = FALSE;
2601 DWORD disposition;
2602 FontSubst *psub;
2604 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2606 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2608 if (disposition == REG_OPENED_EXISTING_KEY)
2610 TRACE("SystemLink key already exists, doing nothing\n");
2611 RegCloseKey(hkey);
2612 return;
2615 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2616 if (!psub) {
2617 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2618 RegCloseKey(hkey);
2619 return;
2622 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2624 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2626 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2627 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2629 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2630 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2631 done = TRUE;
2633 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2635 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2638 RegCloseKey(hkey);
2639 if (!done)
2640 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2641 } else
2642 WARN("failed to create SystemLink key\n");
2646 static BOOL init_freetype(void)
2648 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2649 if(!ft_handle) {
2650 WINE_MESSAGE(
2651 "Wine cannot find the FreeType font library. To enable Wine to\n"
2652 "use TrueType fonts please install a version of FreeType greater than\n"
2653 "or equal to 2.0.5.\n"
2654 "http://www.freetype.org\n");
2655 return FALSE;
2658 #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;}
2660 LOAD_FUNCPTR(FT_Vector_Unit)
2661 LOAD_FUNCPTR(FT_Done_Face)
2662 LOAD_FUNCPTR(FT_Get_Char_Index)
2663 LOAD_FUNCPTR(FT_Get_Module)
2664 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2665 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2666 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2667 LOAD_FUNCPTR(FT_Init_FreeType)
2668 LOAD_FUNCPTR(FT_Load_Glyph)
2669 LOAD_FUNCPTR(FT_Matrix_Multiply)
2670 #ifndef FT_MULFIX_INLINED
2671 LOAD_FUNCPTR(FT_MulFix)
2672 #endif
2673 LOAD_FUNCPTR(FT_New_Face)
2674 LOAD_FUNCPTR(FT_New_Memory_Face)
2675 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2676 LOAD_FUNCPTR(FT_Outline_Transform)
2677 LOAD_FUNCPTR(FT_Outline_Translate)
2678 LOAD_FUNCPTR(FT_Select_Charmap)
2679 LOAD_FUNCPTR(FT_Set_Charmap)
2680 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2681 LOAD_FUNCPTR(FT_Vector_Transform)
2682 LOAD_FUNCPTR(FT_Render_Glyph)
2684 #undef LOAD_FUNCPTR
2685 /* Don't warn if these ones are missing */
2686 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2687 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2688 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2689 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2690 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2691 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2692 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2693 #endif
2694 #ifdef HAVE_FREETYPE_FTWINFNT_H
2695 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2696 #endif
2697 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2698 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2699 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2700 <= 2.0.3 has FT_Sqrt64 */
2701 goto sym_not_found;
2704 if(pFT_Init_FreeType(&library) != 0) {
2705 ERR("Can't init FreeType library\n");
2706 wine_dlclose(ft_handle, NULL, 0);
2707 ft_handle = NULL;
2708 return FALSE;
2710 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2711 if (pFT_Library_Version)
2712 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2714 if (FT_Version.major<=0)
2716 FT_Version.major=2;
2717 FT_Version.minor=0;
2718 FT_Version.patch=5;
2720 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2721 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2722 ((FT_Version.minor << 8) & 0x00ff00) |
2723 ((FT_Version.patch ) & 0x0000ff);
2725 return TRUE;
2727 sym_not_found:
2728 WINE_MESSAGE(
2729 "Wine cannot find certain functions that it needs inside the FreeType\n"
2730 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2731 "FreeType to at least version 2.0.5.\n"
2732 "http://www.freetype.org\n");
2733 wine_dlclose(ft_handle, NULL, 0);
2734 ft_handle = NULL;
2735 return FALSE;
2738 /*************************************************************
2739 * WineEngInit
2741 * Initialize FreeType library and create a list of available faces
2743 BOOL WineEngInit(void)
2745 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2746 static const WCHAR pathW[] = {'P','a','t','h',0};
2747 HKEY hkey;
2748 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2749 WCHAR windowsdir[MAX_PATH];
2750 char *unixname;
2751 HANDLE font_mutex;
2752 const char *data_dir;
2754 TRACE("\n");
2756 /* update locale dependent font info in registry */
2757 update_font_info();
2759 if(!init_freetype()) return FALSE;
2761 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2762 ERR("Failed to create font mutex\n");
2763 return FALSE;
2765 WaitForSingleObject(font_mutex, INFINITE);
2767 delete_external_font_keys();
2769 /* load the system bitmap fonts */
2770 load_system_fonts();
2772 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2773 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2774 strcatW(windowsdir, fontsW);
2775 if((unixname = wine_get_unix_file_name(windowsdir)))
2777 ReadFontDir(unixname, FALSE);
2778 HeapFree(GetProcessHeap(), 0, unixname);
2781 /* load the system truetype fonts */
2782 data_dir = wine_get_data_dir();
2783 if (!data_dir) data_dir = wine_get_build_dir();
2784 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2785 strcpy(unixname, data_dir);
2786 strcat(unixname, "/fonts/");
2787 ReadFontDir(unixname, TRUE);
2788 HeapFree(GetProcessHeap(), 0, unixname);
2791 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2792 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2793 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2794 will skip these. */
2795 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2796 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2797 &hkey) == ERROR_SUCCESS) {
2798 LPWSTR data, valueW;
2799 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2800 &valuelen, &datalen, NULL, NULL);
2802 valuelen++; /* returned value doesn't include room for '\0' */
2803 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2804 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2805 if (valueW && data)
2807 dlen = datalen * sizeof(WCHAR);
2808 vlen = valuelen;
2809 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2810 &dlen) == ERROR_SUCCESS) {
2811 if(data[0] && (data[1] == ':'))
2813 if((unixname = wine_get_unix_file_name(data)))
2815 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2816 HeapFree(GetProcessHeap(), 0, unixname);
2819 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2821 WCHAR pathW[MAX_PATH];
2822 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2823 BOOL added = FALSE;
2825 sprintfW(pathW, fmtW, windowsdir, data);
2826 if((unixname = wine_get_unix_file_name(pathW)))
2828 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2829 HeapFree(GetProcessHeap(), 0, unixname);
2831 if (!added)
2832 load_font_from_data_dir(data);
2834 /* reset dlen and vlen */
2835 dlen = datalen;
2836 vlen = valuelen;
2839 HeapFree(GetProcessHeap(), 0, data);
2840 HeapFree(GetProcessHeap(), 0, valueW);
2841 RegCloseKey(hkey);
2844 load_fontconfig_fonts();
2846 /* then look in any directories that we've specified in the config file */
2847 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2848 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2850 DWORD len;
2851 LPWSTR valueW;
2852 LPSTR valueA, ptr;
2854 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2856 len += sizeof(WCHAR);
2857 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2858 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2860 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2861 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2862 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2863 TRACE( "got font path %s\n", debugstr_a(valueA) );
2864 ptr = valueA;
2865 while (ptr)
2867 LPSTR next = strchr( ptr, ':' );
2868 if (next) *next++ = 0;
2869 ReadFontDir( ptr, TRUE );
2870 ptr = next;
2872 HeapFree( GetProcessHeap(), 0, valueA );
2874 HeapFree( GetProcessHeap(), 0, valueW );
2876 RegCloseKey(hkey);
2879 DumpFontList();
2880 LoadSubstList();
2881 DumpSubstList();
2882 LoadReplaceList();
2883 update_reg_entries();
2885 update_system_links();
2886 init_system_links();
2888 ReleaseMutex(font_mutex);
2889 return TRUE;
2893 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2895 TT_OS2 *pOS2;
2896 TT_HoriHeader *pHori;
2898 LONG ppem;
2900 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2901 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2903 if(height == 0) height = 16;
2905 /* Calc. height of EM square:
2907 * For +ve lfHeight we have
2908 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2909 * Re-arranging gives:
2910 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2912 * For -ve lfHeight we have
2913 * |lfHeight| = ppem
2914 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2915 * with il = winAscent + winDescent - units_per_em]
2919 if(height > 0) {
2920 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2921 ppem = MulDiv(ft_face->units_per_EM, height,
2922 pHori->Ascender - pHori->Descender);
2923 else
2924 ppem = MulDiv(ft_face->units_per_EM, height,
2925 pOS2->usWinAscent + pOS2->usWinDescent);
2927 else
2928 ppem = -height;
2930 return ppem;
2933 static struct font_mapping *map_font_file( const char *name )
2935 struct font_mapping *mapping;
2936 struct stat st;
2937 int fd;
2939 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2940 if (fstat( fd, &st ) == -1) goto error;
2942 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2944 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2946 mapping->refcount++;
2947 close( fd );
2948 return mapping;
2951 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2952 goto error;
2954 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2955 close( fd );
2957 if (mapping->data == MAP_FAILED)
2959 HeapFree( GetProcessHeap(), 0, mapping );
2960 return NULL;
2962 mapping->refcount = 1;
2963 mapping->dev = st.st_dev;
2964 mapping->ino = st.st_ino;
2965 mapping->size = st.st_size;
2966 list_add_tail( &mappings_list, &mapping->entry );
2967 return mapping;
2969 error:
2970 close( fd );
2971 return NULL;
2974 static void unmap_font_file( struct font_mapping *mapping )
2976 if (!--mapping->refcount)
2978 list_remove( &mapping->entry );
2979 munmap( mapping->data, mapping->size );
2980 HeapFree( GetProcessHeap(), 0, mapping );
2984 static LONG load_VDMX(GdiFont*, LONG);
2986 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2988 FT_Error err;
2989 FT_Face ft_face;
2990 void *data_ptr;
2991 DWORD data_size;
2993 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2995 if (face->file)
2997 if (!(font->mapping = map_font_file( face->file )))
2999 WARN("failed to map %s\n", debugstr_a(face->file));
3000 return 0;
3002 data_ptr = font->mapping->data;
3003 data_size = font->mapping->size;
3005 else
3007 data_ptr = face->font_data_ptr;
3008 data_size = face->font_data_size;
3011 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3012 if(err) {
3013 ERR("FT_New_Face rets %d\n", err);
3014 return 0;
3017 /* set it here, as load_VDMX needs it */
3018 font->ft_face = ft_face;
3020 if(FT_IS_SCALABLE(ft_face)) {
3021 /* load the VDMX table if we have one */
3022 font->ppem = load_VDMX(font, height);
3023 if(font->ppem == 0)
3024 font->ppem = calc_ppem_for_height(ft_face, height);
3025 TRACE("height %d => ppem %d\n", height, font->ppem);
3027 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3028 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3029 } else {
3030 font->ppem = height;
3031 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3032 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3034 return ft_face;
3038 static int get_nearest_charset(Face *face, int *cp)
3040 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3041 a single face with the requested charset. The idea is to check if
3042 the selected font supports the current ANSI codepage, if it does
3043 return the corresponding charset, else return the first charset */
3045 CHARSETINFO csi;
3046 int acp = GetACP(), i;
3047 DWORD fs0;
3049 *cp = acp;
3050 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3051 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3052 return csi.ciCharset;
3054 for(i = 0; i < 32; i++) {
3055 fs0 = 1L << i;
3056 if(face->fs.fsCsb[0] & fs0) {
3057 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3058 *cp = csi.ciACP;
3059 return csi.ciCharset;
3061 else
3062 FIXME("TCI failing on %x\n", fs0);
3066 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3067 face->fs.fsCsb[0], face->file);
3068 *cp = acp;
3069 return DEFAULT_CHARSET;
3072 static GdiFont *alloc_font(void)
3074 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3075 ret->gmsize = 1;
3076 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3077 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3078 ret->potm = NULL;
3079 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3080 ret->total_kern_pairs = (DWORD)-1;
3081 ret->kern_pairs = NULL;
3082 list_init(&ret->hfontlist);
3083 list_init(&ret->child_fonts);
3084 return ret;
3087 static void free_font(GdiFont *font)
3089 struct list *cursor, *cursor2;
3090 DWORD i;
3092 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3094 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3095 list_remove(cursor);
3096 if(child->font)
3097 free_font(child->font);
3098 HeapFree(GetProcessHeap(), 0, child);
3101 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3103 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3104 DeleteObject(hfontlist->hfont);
3105 list_remove(&hfontlist->entry);
3106 HeapFree(GetProcessHeap(), 0, hfontlist);
3109 if (font->ft_face) pFT_Done_Face(font->ft_face);
3110 if (font->mapping) unmap_font_file( font->mapping );
3111 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3112 HeapFree(GetProcessHeap(), 0, font->potm);
3113 HeapFree(GetProcessHeap(), 0, font->name);
3114 for (i = 0; i < font->gmsize; i++)
3115 HeapFree(GetProcessHeap(),0,font->gm[i]);
3116 HeapFree(GetProcessHeap(), 0, font->gm);
3117 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3118 HeapFree(GetProcessHeap(), 0, font);
3122 /*************************************************************
3123 * load_VDMX
3125 * load the vdmx entry for the specified height
3128 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3129 ( ( (FT_ULong)_x4 << 24 ) | \
3130 ( (FT_ULong)_x3 << 16 ) | \
3131 ( (FT_ULong)_x2 << 8 ) | \
3132 (FT_ULong)_x1 )
3134 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3136 typedef struct {
3137 BYTE bCharSet;
3138 BYTE xRatio;
3139 BYTE yStartRatio;
3140 BYTE yEndRatio;
3141 } Ratios;
3143 typedef struct {
3144 WORD recs;
3145 BYTE startsz;
3146 BYTE endsz;
3147 } VDMX_group;
3149 static LONG load_VDMX(GdiFont *font, LONG height)
3151 WORD hdr[3], tmp;
3152 VDMX_group group;
3153 BYTE devXRatio, devYRatio;
3154 USHORT numRecs, numRatios;
3155 DWORD result, offset = -1;
3156 LONG ppem = 0;
3157 int i;
3159 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3161 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3162 return ppem;
3164 /* FIXME: need the real device aspect ratio */
3165 devXRatio = 1;
3166 devYRatio = 1;
3168 numRecs = GET_BE_WORD(hdr[1]);
3169 numRatios = GET_BE_WORD(hdr[2]);
3171 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3172 for(i = 0; i < numRatios; i++) {
3173 Ratios ratio;
3175 offset = (3 * 2) + (i * sizeof(Ratios));
3176 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3177 offset = -1;
3179 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3181 if((ratio.xRatio == 0 &&
3182 ratio.yStartRatio == 0 &&
3183 ratio.yEndRatio == 0) ||
3184 (devXRatio == ratio.xRatio &&
3185 devYRatio >= ratio.yStartRatio &&
3186 devYRatio <= ratio.yEndRatio))
3188 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3189 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3190 offset = GET_BE_WORD(tmp);
3191 break;
3195 if(offset == -1) {
3196 FIXME("No suitable ratio found\n");
3197 return ppem;
3200 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3201 USHORT recs;
3202 BYTE startsz, endsz;
3203 WORD *vTable;
3205 recs = GET_BE_WORD(group.recs);
3206 startsz = group.startsz;
3207 endsz = group.endsz;
3209 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3211 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3212 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3213 if(result == GDI_ERROR) {
3214 FIXME("Failed to retrieve vTable\n");
3215 goto end;
3218 if(height > 0) {
3219 for(i = 0; i < recs; i++) {
3220 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3221 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3222 ppem = GET_BE_WORD(vTable[i * 3]);
3224 if(yMax + -yMin == height) {
3225 font->yMax = yMax;
3226 font->yMin = yMin;
3227 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3228 break;
3230 if(yMax + -yMin > height) {
3231 if(--i < 0) {
3232 ppem = 0;
3233 goto end; /* failed */
3235 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3236 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3237 ppem = GET_BE_WORD(vTable[i * 3]);
3238 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3239 break;
3242 if(!font->yMax) {
3243 ppem = 0;
3244 TRACE("ppem not found for height %d\n", height);
3247 end:
3248 HeapFree(GetProcessHeap(), 0, vTable);
3251 return ppem;
3254 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3256 if(font->font_desc.hash != fd->hash) return TRUE;
3257 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3258 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3259 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3260 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3263 static void calc_hash(FONT_DESC *pfd)
3265 DWORD hash = 0, *ptr, two_chars;
3266 WORD *pwc;
3267 unsigned int i;
3269 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3270 hash ^= *ptr;
3271 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3272 hash ^= *ptr;
3273 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3274 two_chars = *ptr;
3275 pwc = (WCHAR *)&two_chars;
3276 if(!*pwc) break;
3277 *pwc = toupperW(*pwc);
3278 pwc++;
3279 *pwc = toupperW(*pwc);
3280 hash ^= two_chars;
3281 if(!*pwc) break;
3283 hash ^= !pfd->can_use_bitmap;
3284 pfd->hash = hash;
3285 return;
3288 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3290 GdiFont *ret;
3291 FONT_DESC fd;
3292 HFONTLIST *hflist;
3293 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3295 fd.lf = *plf;
3296 fd.matrix = *pmat;
3297 fd.can_use_bitmap = can_use_bitmap;
3298 calc_hash(&fd);
3300 /* try the child list */
3301 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3302 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3303 if(!fontcmp(ret, &fd)) {
3304 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3305 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3306 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3307 if(hflist->hfont == hfont)
3308 return ret;
3313 /* try the in-use list */
3314 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3315 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3316 if(!fontcmp(ret, &fd)) {
3317 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3318 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3319 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3320 if(hflist->hfont == hfont)
3321 return ret;
3323 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3324 hflist->hfont = hfont;
3325 list_add_head(&ret->hfontlist, &hflist->entry);
3326 return ret;
3330 /* then the unused list */
3331 font_elem_ptr = list_head(&unused_gdi_font_list);
3332 while(font_elem_ptr) {
3333 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3334 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3335 if(!fontcmp(ret, &fd)) {
3336 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3337 assert(list_empty(&ret->hfontlist));
3338 TRACE("Found %p in unused list\n", ret);
3339 list_remove(&ret->entry);
3340 list_add_head(&gdi_font_list, &ret->entry);
3341 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3342 hflist->hfont = hfont;
3343 list_add_head(&ret->hfontlist, &hflist->entry);
3344 return ret;
3347 return NULL;
3350 static void add_to_cache(GdiFont *font)
3352 static DWORD cache_num = 1;
3354 font->cache_num = cache_num++;
3355 list_add_head(&gdi_font_list, &font->entry);
3358 /*************************************************************
3359 * create_child_font_list
3361 static BOOL create_child_font_list(GdiFont *font)
3363 BOOL ret = FALSE;
3364 SYSTEM_LINKS *font_link;
3365 CHILD_FONT *font_link_entry, *new_child;
3366 FontSubst *psub;
3367 WCHAR* font_name;
3369 psub = get_font_subst(&font_subst_list, font->name, -1);
3370 font_name = psub ? psub->to.name : font->name;
3371 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3373 if(!strcmpiW(font_link->font_name, font_name))
3375 TRACE("found entry in system list\n");
3376 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3378 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3379 new_child->face = font_link_entry->face;
3380 new_child->font = NULL;
3381 list_add_tail(&font->child_fonts, &new_child->entry);
3382 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3384 ret = TRUE;
3385 break;
3389 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3390 * Sans Serif. This is how asian windows get default fallbacks for fonts
3392 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3393 font->charset != OEM_CHARSET &&
3394 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3395 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3397 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3399 TRACE("found entry in default fallback list\n");
3400 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3402 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3403 new_child->face = font_link_entry->face;
3404 new_child->font = NULL;
3405 list_add_tail(&font->child_fonts, &new_child->entry);
3406 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3408 ret = TRUE;
3409 break;
3413 return ret;
3416 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3418 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3420 if (pFT_Set_Charmap)
3422 FT_Int i;
3423 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3425 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3427 for (i = 0; i < ft_face->num_charmaps; i++)
3429 if (ft_face->charmaps[i]->encoding == encoding)
3431 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3432 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3434 switch (ft_face->charmaps[i]->platform_id)
3436 default:
3437 cmap_def = ft_face->charmaps[i];
3438 break;
3439 case 0: /* Apple Unicode */
3440 cmap0 = ft_face->charmaps[i];
3441 break;
3442 case 1: /* Macintosh */
3443 cmap1 = ft_face->charmaps[i];
3444 break;
3445 case 2: /* ISO */
3446 cmap2 = ft_face->charmaps[i];
3447 break;
3448 case 3: /* Microsoft */
3449 cmap3 = ft_face->charmaps[i];
3450 break;
3454 if (cmap3) /* prefer Microsoft cmap table */
3455 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3456 else if (cmap1)
3457 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3458 else if (cmap2)
3459 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3460 else if (cmap0)
3461 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3462 else if (cmap_def)
3463 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3465 return ft_err == FT_Err_Ok;
3468 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3471 /*************************************************************
3472 * WineEngCreateFontInstance
3475 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3477 GdiFont *ret;
3478 Face *face, *best, *best_bitmap;
3479 Family *family, *last_resort_family;
3480 struct list *family_elem_ptr, *face_elem_ptr;
3481 INT height, width = 0;
3482 unsigned int score = 0, new_score;
3483 signed int diff = 0, newdiff;
3484 BOOL bd, it, can_use_bitmap;
3485 LOGFONTW lf;
3486 CHARSETINFO csi;
3487 HFONTLIST *hflist;
3488 FMAT2 dcmat;
3489 FontSubst *psub = NULL;
3491 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3492 lf.lfWidth = abs(lf.lfWidth);
3494 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3496 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3497 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3498 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3499 lf.lfEscapement);
3501 if(dc->GraphicsMode == GM_ADVANCED)
3502 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3503 else
3505 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3506 font scaling abilities. */
3507 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3508 dcmat.eM21 = dcmat.eM12 = 0;
3511 /* Try to avoid not necessary glyph transformations */
3512 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3514 lf.lfHeight *= fabs(dcmat.eM11);
3515 lf.lfWidth *= fabs(dcmat.eM11);
3516 dcmat.eM11 = dcmat.eM22 = 1.0;
3519 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3520 dcmat.eM21, dcmat.eM22);
3522 GDI_CheckNotLock();
3523 EnterCriticalSection( &freetype_cs );
3525 /* check the cache first */
3526 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3527 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3528 LeaveCriticalSection( &freetype_cs );
3529 return ret;
3532 TRACE("not in cache\n");
3533 if(list_empty(&font_list)) /* No fonts installed */
3535 TRACE("No fonts installed\n");
3536 LeaveCriticalSection( &freetype_cs );
3537 return NULL;
3540 ret = alloc_font();
3542 ret->font_desc.matrix = dcmat;
3543 ret->font_desc.lf = lf;
3544 ret->font_desc.can_use_bitmap = can_use_bitmap;
3545 calc_hash(&ret->font_desc);
3546 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3547 hflist->hfont = hfont;
3548 list_add_head(&ret->hfontlist, &hflist->entry);
3550 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3551 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3552 original value lfCharSet. Note this is a special case for
3553 Symbol and doesn't happen at least for "Wingdings*" */
3555 if(!strcmpiW(lf.lfFaceName, SymbolW))
3556 lf.lfCharSet = SYMBOL_CHARSET;
3558 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3559 switch(lf.lfCharSet) {
3560 case DEFAULT_CHARSET:
3561 csi.fs.fsCsb[0] = 0;
3562 break;
3563 default:
3564 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3565 csi.fs.fsCsb[0] = 0;
3566 break;
3570 family = NULL;
3571 if(lf.lfFaceName[0] != '\0') {
3572 SYSTEM_LINKS *font_link;
3573 CHILD_FONT *font_link_entry;
3574 LPWSTR FaceName = lf.lfFaceName;
3577 * Check for a leading '@' this signals that the font is being
3578 * requested in tategaki mode (vertical writing substitution) but
3579 * does not affect the fontface that is to be selected.
3581 if (lf.lfFaceName[0]=='@')
3582 FaceName = &lf.lfFaceName[1];
3584 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3586 if(psub) {
3587 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3588 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3589 if (psub->to.charset != -1)
3590 lf.lfCharSet = psub->to.charset;
3593 /* We want a match on name and charset or just name if
3594 charset was DEFAULT_CHARSET. If the latter then
3595 we fixup the returned charset later in get_nearest_charset
3596 where we'll either use the charset of the current ansi codepage
3597 or if that's unavailable the first charset that the font supports.
3599 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3600 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3601 if (!strcmpiW(family->FamilyName, FaceName) ||
3602 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3604 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3605 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3606 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3607 if(face->scalable || can_use_bitmap)
3608 goto found;
3614 * Try check the SystemLink list first for a replacement font.
3615 * We may find good replacements there.
3617 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3619 if(!strcmpiW(font_link->font_name, FaceName) ||
3620 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3622 TRACE("found entry in system list\n");
3623 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3625 face = font_link_entry->face;
3626 family = face->family;
3627 if(csi.fs.fsCsb[0] &
3628 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3630 if(face->scalable || can_use_bitmap)
3631 goto found;
3638 psub = NULL; /* substitution is no more relevant */
3640 /* If requested charset was DEFAULT_CHARSET then try using charset
3641 corresponding to the current ansi codepage */
3642 if (!csi.fs.fsCsb[0])
3644 INT acp = GetACP();
3645 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3646 FIXME("TCI failed on codepage %d\n", acp);
3647 csi.fs.fsCsb[0] = 0;
3648 } else
3649 lf.lfCharSet = csi.ciCharset;
3652 /* Face families are in the top 4 bits of lfPitchAndFamily,
3653 so mask with 0xF0 before testing */
3655 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3656 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3657 strcpyW(lf.lfFaceName, defFixed);
3658 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3659 strcpyW(lf.lfFaceName, defSerif);
3660 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3661 strcpyW(lf.lfFaceName, defSans);
3662 else
3663 strcpyW(lf.lfFaceName, defSans);
3664 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3665 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3666 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3667 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3668 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3669 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3670 if(face->scalable || can_use_bitmap)
3671 goto found;
3676 last_resort_family = NULL;
3677 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3678 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3679 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3680 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3681 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3682 if(face->scalable)
3683 goto found;
3684 if(can_use_bitmap && !last_resort_family)
3685 last_resort_family = family;
3690 if(last_resort_family) {
3691 family = last_resort_family;
3692 csi.fs.fsCsb[0] = 0;
3693 goto found;
3696 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3697 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3698 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3699 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3700 if(face->scalable) {
3701 csi.fs.fsCsb[0] = 0;
3702 WARN("just using first face for now\n");
3703 goto found;
3705 if(can_use_bitmap && !last_resort_family)
3706 last_resort_family = family;
3709 if(!last_resort_family) {
3710 FIXME("can't find a single appropriate font - bailing\n");
3711 free_font(ret);
3712 LeaveCriticalSection( &freetype_cs );
3713 return NULL;
3716 WARN("could only find a bitmap font - this will probably look awful!\n");
3717 family = last_resort_family;
3718 csi.fs.fsCsb[0] = 0;
3720 found:
3721 it = lf.lfItalic ? 1 : 0;
3722 bd = lf.lfWeight > 550 ? 1 : 0;
3724 height = lf.lfHeight;
3726 face = best = best_bitmap = NULL;
3727 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3729 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3731 BOOL italic, bold;
3733 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3734 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3735 new_score = (italic ^ it) + (bold ^ bd);
3736 if(!best || new_score <= score)
3738 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3739 italic, bold, it, bd);
3740 score = new_score;
3741 best = face;
3742 if(best->scalable && score == 0) break;
3743 if(!best->scalable)
3745 if(height > 0)
3746 newdiff = height - (signed int)(best->size.height);
3747 else
3748 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3749 if(!best_bitmap || new_score < score ||
3750 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3752 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3753 diff = newdiff;
3754 best_bitmap = best;
3755 if(score == 0 && diff == 0) break;
3761 if(best)
3762 face = best->scalable ? best : best_bitmap;
3763 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3764 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3766 ret->fs = face->fs;
3768 if(csi.fs.fsCsb[0]) {
3769 ret->charset = lf.lfCharSet;
3770 ret->codepage = csi.ciACP;
3772 else
3773 ret->charset = get_nearest_charset(face, &ret->codepage);
3775 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3776 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3778 ret->aveWidth = height ? lf.lfWidth : 0;
3780 if(!face->scalable) {
3781 /* Windows uses integer scaling factors for bitmap fonts */
3782 INT scale, scaled_height;
3783 GdiFont *cachedfont;
3785 /* FIXME: rotation of bitmap fonts is ignored */
3786 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3787 if (ret->aveWidth)
3788 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3789 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3790 dcmat.eM11 = dcmat.eM22 = 1.0;
3791 /* As we changed the matrix, we need to search the cache for the font again,
3792 * otherwise we might explode the cache. */
3793 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3794 TRACE("Found cached font after non-scalable matrix rescale!\n");
3795 free_font( ret );
3796 LeaveCriticalSection( &freetype_cs );
3797 return cachedfont;
3799 calc_hash(&ret->font_desc);
3801 if (height != 0) height = diff;
3802 height += face->size.height;
3804 scale = (height + face->size.height - 1) / face->size.height;
3805 scaled_height = scale * face->size.height;
3806 /* Only jump to the next height if the difference <= 25% original height */
3807 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3808 /* The jump between unscaled and doubled is delayed by 1 */
3809 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3810 ret->scale_y = scale;
3812 width = face->size.x_ppem >> 6;
3813 height = face->size.y_ppem >> 6;
3815 else
3816 ret->scale_y = 1.0;
3817 TRACE("font scale y: %f\n", ret->scale_y);
3819 ret->ft_face = OpenFontFace(ret, face, width, height);
3821 if (!ret->ft_face)
3823 free_font( ret );
3824 LeaveCriticalSection( &freetype_cs );
3825 return 0;
3828 ret->ntmFlags = face->ntmFlags;
3830 if (ret->charset == SYMBOL_CHARSET &&
3831 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3832 /* No ops */
3834 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3835 /* No ops */
3837 else {
3838 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3841 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3842 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3843 ret->underline = lf.lfUnderline ? 0xff : 0;
3844 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3845 create_child_font_list(ret);
3847 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3849 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3850 if (length != GDI_ERROR)
3852 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3853 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3854 TRACE("Loaded GSUB table of %i bytes\n",length);
3858 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3860 add_to_cache(ret);
3861 LeaveCriticalSection( &freetype_cs );
3862 return ret;
3865 static void dump_gdi_font_list(void)
3867 GdiFont *gdiFont;
3868 struct list *elem_ptr;
3870 TRACE("---------- gdiFont Cache ----------\n");
3871 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3872 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3873 TRACE("gdiFont=%p %s %d\n",
3874 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3877 TRACE("---------- Unused gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3879 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3884 TRACE("---------- Child gdiFont Cache ----------\n");
3885 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3886 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3887 TRACE("gdiFont=%p %s %d\n",
3888 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3892 /*************************************************************
3893 * WineEngDestroyFontInstance
3895 * free the gdiFont associated with this handle
3898 BOOL WineEngDestroyFontInstance(HFONT handle)
3900 GdiFont *gdiFont;
3901 HFONTLIST *hflist;
3902 BOOL ret = FALSE;
3903 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3904 int i = 0;
3906 GDI_CheckNotLock();
3907 EnterCriticalSection( &freetype_cs );
3909 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3911 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3912 while(hfontlist_elem_ptr) {
3913 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3914 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3915 if(hflist->hfont == handle) {
3916 TRACE("removing child font %p from child list\n", gdiFont);
3917 list_remove(&gdiFont->entry);
3918 LeaveCriticalSection( &freetype_cs );
3919 return TRUE;
3924 TRACE("destroying hfont=%p\n", handle);
3925 if(TRACE_ON(font))
3926 dump_gdi_font_list();
3928 font_elem_ptr = list_head(&gdi_font_list);
3929 while(font_elem_ptr) {
3930 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3931 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3933 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3934 while(hfontlist_elem_ptr) {
3935 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3936 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3937 if(hflist->hfont == handle) {
3938 list_remove(&hflist->entry);
3939 HeapFree(GetProcessHeap(), 0, hflist);
3940 ret = TRUE;
3943 if(list_empty(&gdiFont->hfontlist)) {
3944 TRACE("Moving to Unused list\n");
3945 list_remove(&gdiFont->entry);
3946 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3951 font_elem_ptr = list_head(&unused_gdi_font_list);
3952 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3953 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3954 while(font_elem_ptr) {
3955 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3956 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3957 TRACE("freeing %p\n", gdiFont);
3958 list_remove(&gdiFont->entry);
3959 free_font(gdiFont);
3961 LeaveCriticalSection( &freetype_cs );
3962 return ret;
3965 /***************************************************
3966 * create_enum_charset_list
3968 * This function creates charset enumeration list because in DEFAULT_CHARSET
3969 * case, the ANSI codepage's charset takes precedence over other charsets.
3970 * This function works as a filter other than DEFAULT_CHARSET case.
3972 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
3974 CHARSETINFO csi;
3975 DWORD n = 0;
3977 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
3978 csi.fs.fsCsb[0] != 0) {
3979 list->element[n].mask = csi.fs.fsCsb[0];
3980 list->element[n].charset = csi.ciCharset;
3981 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
3982 n++;
3984 else { /* charset is DEFAULT_CHARSET or invalid. */
3985 INT acp, i;
3987 /* Set the current codepage's charset as the first element. */
3988 acp = GetACP();
3989 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
3990 csi.fs.fsCsb[0] != 0) {
3991 list->element[n].mask = csi.fs.fsCsb[0];
3992 list->element[n].charset = csi.ciCharset;
3993 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
3994 n++;
3997 /* Fill out left elements. */
3998 for (i = 0; i < 32; i++) {
3999 FONTSIGNATURE fs;
4000 fs.fsCsb[0] = 1L << i;
4001 fs.fsCsb[1] = 0;
4002 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4003 continue; /* skip, already added. */
4004 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4005 continue; /* skip, this is an invalid fsCsb bit. */
4007 list->element[n].mask = fs.fsCsb[0];
4008 list->element[n].charset = csi.ciCharset;
4009 list->element[n].name = ElfScriptsW[i];
4010 n++;
4013 list->total = n;
4015 return n;
4018 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4019 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4021 GdiFont *font;
4022 LONG width, height;
4024 if (face->cached_enum_data)
4026 TRACE("Cached\n");
4027 *pelf = face->cached_enum_data->elf;
4028 *pntm = face->cached_enum_data->ntm;
4029 *ptype = face->cached_enum_data->type;
4030 return;
4033 font = alloc_font();
4035 if(face->scalable) {
4036 height = -2048; /* 2048 is the most common em size */
4037 width = 0;
4038 } else {
4039 height = face->size.y_ppem >> 6;
4040 width = face->size.x_ppem >> 6;
4042 font->scale_y = 1.0;
4044 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4046 free_font(font);
4047 return;
4050 font->name = strdupW(face->family->FamilyName);
4051 font->ntmFlags = face->ntmFlags;
4053 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4055 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4057 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4059 lstrcpynW(pelf->elfLogFont.lfFaceName,
4060 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4061 LF_FACESIZE);
4062 lstrcpynW(pelf->elfFullName,
4063 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4064 LF_FULLFACESIZE);
4065 lstrcpynW(pelf->elfStyle,
4066 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4067 LF_FACESIZE);
4069 else
4071 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4073 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4075 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4076 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4077 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4080 pntm->ntmTm.ntmFlags = face->ntmFlags;
4081 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4082 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4083 pntm->ntmFontSig = face->fs;
4085 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4087 pelf->elfLogFont.lfEscapement = 0;
4088 pelf->elfLogFont.lfOrientation = 0;
4089 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4090 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4091 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4092 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4093 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4094 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4095 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4096 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4097 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4098 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4099 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4101 *ptype = 0;
4102 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4103 *ptype |= TRUETYPE_FONTTYPE;
4104 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4105 *ptype |= DEVICE_FONTTYPE;
4106 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4107 *ptype |= RASTER_FONTTYPE;
4109 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4110 if (face->cached_enum_data)
4112 face->cached_enum_data->elf = *pelf;
4113 face->cached_enum_data->ntm = *pntm;
4114 face->cached_enum_data->type = *ptype;
4117 free_font(font);
4120 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4122 struct list *face_elem_ptr;
4124 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4126 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4128 static const WCHAR spaceW[] = { ' ',0 };
4129 WCHAR full_family_name[LF_FULLFACESIZE];
4130 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4132 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4134 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4135 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4136 continue;
4139 strcpyW(full_family_name, family->FamilyName);
4140 strcatW(full_family_name, spaceW);
4141 strcatW(full_family_name, face->StyleName);
4142 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4145 return FALSE;
4148 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4150 static const WCHAR spaceW[] = { ' ',0 };
4151 WCHAR full_family_name[LF_FULLFACESIZE];
4153 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4155 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4157 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4158 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4159 return FALSE;
4162 strcpyW(full_family_name, face->family->FamilyName);
4163 strcatW(full_family_name, spaceW);
4164 strcatW(full_family_name, face->StyleName);
4165 return !strcmpiW(lf->lfFaceName, full_family_name);
4168 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4169 FONTENUMPROCW proc, LPARAM lparam)
4171 ENUMLOGFONTEXW elf;
4172 NEWTEXTMETRICEXW ntm;
4173 DWORD type = 0;
4174 int i;
4176 GetEnumStructs(face, &elf, &ntm, &type);
4177 for(i = 0; i < list->total; i++) {
4178 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4179 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4180 strcpyW(elf.elfScript, OEM_DOSW);
4181 i = 32; /* break out of loop */
4182 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4183 continue;
4184 else {
4185 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4186 if(list->element[i].name)
4187 strcpyW(elf.elfScript, list->element[i].name);
4188 else
4189 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4191 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4192 debugstr_w(elf.elfLogFont.lfFaceName),
4193 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4194 list->element[i].charset, type, debugstr_w(elf.elfScript),
4195 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4196 ntm.ntmTm.ntmFlags);
4197 /* release section before callback (FIXME) */
4198 LeaveCriticalSection( &freetype_cs );
4199 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4200 EnterCriticalSection( &freetype_cs );
4202 return TRUE;
4205 /*************************************************************
4206 * WineEngEnumFonts
4209 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4211 Family *family;
4212 Face *face;
4213 struct list *family_elem_ptr, *face_elem_ptr;
4214 LOGFONTW lf;
4215 struct enum_charset_list enum_charsets;
4217 if (!plf)
4219 lf.lfCharSet = DEFAULT_CHARSET;
4220 lf.lfPitchAndFamily = 0;
4221 lf.lfFaceName[0] = 0;
4222 plf = &lf;
4225 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4227 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4229 GDI_CheckNotLock();
4230 EnterCriticalSection( &freetype_cs );
4231 if(plf->lfFaceName[0]) {
4232 FontSubst *psub;
4233 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4235 if(psub) {
4236 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4237 debugstr_w(psub->to.name));
4238 lf = *plf;
4239 strcpyW(lf.lfFaceName, psub->to.name);
4240 plf = &lf;
4243 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4244 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4245 if(family_matches(family, plf)) {
4246 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4247 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4248 if (!face_matches(face, plf)) continue;
4249 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4253 } else {
4254 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4255 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4256 face_elem_ptr = list_head(&family->faces);
4257 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4258 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4261 LeaveCriticalSection( &freetype_cs );
4262 return 1;
4265 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4267 pt->x.value = vec->x >> 6;
4268 pt->x.fract = (vec->x & 0x3f) << 10;
4269 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4270 pt->y.value = vec->y >> 6;
4271 pt->y.fract = (vec->y & 0x3f) << 10;
4272 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4273 return;
4276 /***************************************************
4277 * According to the MSDN documentation on WideCharToMultiByte,
4278 * certain codepages cannot set the default_used parameter.
4279 * This returns TRUE if the codepage can set that parameter, false else
4280 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4282 static BOOL codepage_sets_default_used(UINT codepage)
4284 switch (codepage)
4286 case CP_UTF7:
4287 case CP_UTF8:
4288 case CP_SYMBOL:
4289 return FALSE;
4290 default:
4291 return TRUE;
4296 * GSUB Table handling functions
4299 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4301 const GSUB_CoverageFormat1* cf1;
4303 cf1 = table;
4305 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4307 int count = GET_BE_WORD(cf1->GlyphCount);
4308 int i;
4309 TRACE("Coverage Format 1, %i glyphs\n",count);
4310 for (i = 0; i < count; i++)
4311 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4312 return i;
4313 return -1;
4315 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4317 const GSUB_CoverageFormat2* cf2;
4318 int i;
4319 int count;
4320 cf2 = (const GSUB_CoverageFormat2*)cf1;
4322 count = GET_BE_WORD(cf2->RangeCount);
4323 TRACE("Coverage Format 2, %i ranges\n",count);
4324 for (i = 0; i < count; i++)
4326 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4327 return -1;
4328 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4329 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4331 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4332 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4335 return -1;
4337 else
4338 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4340 return -1;
4343 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4345 const GSUB_ScriptList *script;
4346 const GSUB_Script *deflt = NULL;
4347 int i;
4348 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4350 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4351 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4353 const GSUB_Script *scr;
4354 int offset;
4356 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4357 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4359 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4360 return scr;
4361 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4362 deflt = scr;
4364 return deflt;
4367 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4369 int i;
4370 int offset;
4371 const GSUB_LangSys *Lang;
4373 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4375 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4377 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4378 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4380 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4381 return Lang;
4383 offset = GET_BE_WORD(script->DefaultLangSys);
4384 if (offset)
4386 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4387 return Lang;
4389 return NULL;
4392 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4394 int i;
4395 const GSUB_FeatureList *feature;
4396 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4398 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4399 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4401 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4402 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4404 const GSUB_Feature *feat;
4405 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4406 return feat;
4409 return NULL;
4412 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4414 int i;
4415 int offset;
4416 const GSUB_LookupList *lookup;
4417 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4419 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4420 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4422 const GSUB_LookupTable *look;
4423 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4424 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4425 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4426 if (GET_BE_WORD(look->LookupType) != 1)
4427 FIXME("We only handle SubType 1\n");
4428 else
4430 int j;
4432 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4434 const GSUB_SingleSubstFormat1 *ssf1;
4435 offset = GET_BE_WORD(look->SubTable[j]);
4436 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4437 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4439 int offset = GET_BE_WORD(ssf1->Coverage);
4440 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4441 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4443 TRACE(" Glyph 0x%x ->",glyph);
4444 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4445 TRACE(" 0x%x\n",glyph);
4448 else
4450 const GSUB_SingleSubstFormat2 *ssf2;
4451 INT index;
4452 INT offset;
4454 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4455 offset = GET_BE_WORD(ssf1->Coverage);
4456 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4457 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4458 TRACE(" Coverage index %i\n",index);
4459 if (index != -1)
4461 TRACE(" Glyph is 0x%x ->",glyph);
4462 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4463 TRACE("0x%x\n",glyph);
4469 return glyph;
4472 static const char* get_opentype_script(const GdiFont *font)
4475 * I am not sure if this is the correct way to generate our script tag
4478 switch (font->charset)
4480 case ANSI_CHARSET: return "latn";
4481 case BALTIC_CHARSET: return "latn"; /* ?? */
4482 case CHINESEBIG5_CHARSET: return "hani";
4483 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4484 case GB2312_CHARSET: return "hani";
4485 case GREEK_CHARSET: return "grek";
4486 case HANGUL_CHARSET: return "hang";
4487 case RUSSIAN_CHARSET: return "cyrl";
4488 case SHIFTJIS_CHARSET: return "kana";
4489 case TURKISH_CHARSET: return "latn"; /* ?? */
4490 case VIETNAMESE_CHARSET: return "latn";
4491 case JOHAB_CHARSET: return "latn"; /* ?? */
4492 case ARABIC_CHARSET: return "arab";
4493 case HEBREW_CHARSET: return "hebr";
4494 case THAI_CHARSET: return "thai";
4495 default: return "latn";
4499 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4501 const GSUB_Header *header;
4502 const GSUB_Script *script;
4503 const GSUB_LangSys *language;
4504 const GSUB_Feature *feature;
4506 if (!font->GSUB_Table)
4507 return glyph;
4509 header = font->GSUB_Table;
4511 script = GSUB_get_script_table(header, get_opentype_script(font));
4512 if (!script)
4514 TRACE("Script not found\n");
4515 return glyph;
4517 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4518 if (!language)
4520 TRACE("Language not found\n");
4521 return glyph;
4523 feature = GSUB_get_feature(header, language, "vrt2");
4524 if (!feature)
4525 feature = GSUB_get_feature(header, language, "vert");
4526 if (!feature)
4528 TRACE("vrt2/vert feature not found\n");
4529 return glyph;
4531 return GSUB_apply_feature(header, feature, glyph);
4534 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4536 FT_UInt glyphId;
4538 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4539 WCHAR wc = (WCHAR)glyph;
4540 BOOL default_used;
4541 BOOL *default_used_pointer;
4542 FT_UInt ret;
4543 char buf;
4544 default_used_pointer = NULL;
4545 default_used = FALSE;
4546 if (codepage_sets_default_used(font->codepage))
4547 default_used_pointer = &default_used;
4548 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4549 ret = 0;
4550 else
4551 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4552 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4553 return get_GSUB_vert_glyph(font,ret);
4556 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4557 glyph = glyph + 0xf000;
4558 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4559 return get_GSUB_vert_glyph(font,glyphId);
4562 /*************************************************************
4563 * WineEngGetGlyphIndices
4566 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4567 LPWORD pgi, DWORD flags)
4569 int i;
4570 int default_char = -1;
4572 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4574 for(i = 0; i < count; i++)
4576 pgi[i] = get_glyph_index(font, lpstr[i]);
4577 if (pgi[i] == 0)
4579 if (default_char == -1)
4581 if (FT_IS_SFNT(font->ft_face))
4583 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4584 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4586 else
4588 TEXTMETRICW textm;
4589 WineEngGetTextMetrics(font, &textm);
4590 default_char = textm.tmDefaultChar;
4593 pgi[i] = default_char;
4596 return count;
4599 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4601 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4602 return !memcmp(matrix, &identity, sizeof(FMAT2));
4605 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4607 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4608 return !memcmp(matrix, &identity, sizeof(MAT2));
4611 /*************************************************************
4612 * WineEngGetGlyphOutline
4614 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4615 * except that the first parameter is the HWINEENGFONT of the font in
4616 * question rather than an HDC.
4619 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4620 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4621 const MAT2* lpmat)
4623 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4624 FT_Face ft_face = incoming_font->ft_face;
4625 GdiFont *font = incoming_font;
4626 FT_UInt glyph_index;
4627 DWORD width, height, pitch, needed = 0;
4628 FT_Bitmap ft_bitmap;
4629 FT_Error err;
4630 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4631 FT_Angle angle = 0;
4632 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4633 double widthRatio = 1.0;
4634 FT_Matrix transMat = identityMat;
4635 FT_Matrix transMatUnrotated;
4636 BOOL needsTransform = FALSE;
4637 BOOL tategaki = (font->GSUB_Table != NULL);
4638 UINT original_index;
4640 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4641 buflen, buf, lpmat);
4643 TRACE("font transform %f %f %f %f\n",
4644 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4645 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4647 GDI_CheckNotLock();
4648 EnterCriticalSection( &freetype_cs );
4650 if(format & GGO_GLYPH_INDEX) {
4651 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4652 original_index = glyph;
4653 format &= ~GGO_GLYPH_INDEX;
4654 } else {
4655 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4656 ft_face = font->ft_face;
4657 original_index = glyph_index;
4660 if(format & GGO_UNHINTED) {
4661 load_flags |= FT_LOAD_NO_HINTING;
4662 format &= ~GGO_UNHINTED;
4665 /* tategaki never appears to happen to lower glyph index */
4666 if (glyph_index < TATEGAKI_LOWER_BOUND )
4667 tategaki = FALSE;
4669 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4670 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4671 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4672 font->gmsize * sizeof(GM*));
4673 } else {
4674 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4675 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4677 *lpgm = FONT_GM(font,original_index)->gm;
4678 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4679 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4680 lpgm->gmCellIncX, lpgm->gmCellIncY);
4681 LeaveCriticalSection( &freetype_cs );
4682 return 1; /* FIXME */
4686 if (!font->gm[original_index / GM_BLOCK_SIZE])
4687 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4689 /* Scaling factor */
4690 if (font->aveWidth)
4692 TEXTMETRICW tm;
4694 WineEngGetTextMetrics(font, &tm);
4696 widthRatio = (double)font->aveWidth;
4697 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4699 else
4700 widthRatio = font->scale_y;
4702 /* Scaling transform */
4703 if (widthRatio != 1.0 || font->scale_y != 1.0)
4705 FT_Matrix scaleMat;
4706 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4707 scaleMat.xy = 0;
4708 scaleMat.yx = 0;
4709 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4711 pFT_Matrix_Multiply(&scaleMat, &transMat);
4712 needsTransform = TRUE;
4715 /* Slant transform */
4716 if (font->fake_italic) {
4717 FT_Matrix slantMat;
4719 slantMat.xx = (1 << 16);
4720 slantMat.xy = ((1 << 16) >> 2);
4721 slantMat.yx = 0;
4722 slantMat.yy = (1 << 16);
4723 pFT_Matrix_Multiply(&slantMat, &transMat);
4724 needsTransform = TRUE;
4727 /* Rotation transform */
4728 transMatUnrotated = transMat;
4729 if(font->orientation && !tategaki) {
4730 FT_Matrix rotationMat;
4731 FT_Vector vecAngle;
4732 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4733 pFT_Vector_Unit(&vecAngle, angle);
4734 rotationMat.xx = vecAngle.x;
4735 rotationMat.xy = -vecAngle.y;
4736 rotationMat.yx = -rotationMat.xy;
4737 rotationMat.yy = rotationMat.xx;
4739 pFT_Matrix_Multiply(&rotationMat, &transMat);
4740 needsTransform = TRUE;
4743 /* World transform */
4744 if (!is_identity_FMAT2(&font->font_desc.matrix))
4746 FT_Matrix worldMat;
4747 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4748 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4749 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4750 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4751 pFT_Matrix_Multiply(&worldMat, &transMat);
4752 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4753 needsTransform = TRUE;
4756 /* Extra transformation specified by caller */
4757 if (!is_identity_MAT2(lpmat))
4759 FT_Matrix extraMat;
4760 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4761 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4762 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4763 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4764 pFT_Matrix_Multiply(&extraMat, &transMat);
4765 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4766 needsTransform = TRUE;
4769 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4770 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4771 format == GGO_GRAY8_BITMAP))
4773 load_flags |= FT_LOAD_NO_BITMAP;
4776 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4778 if(err) {
4779 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4780 LeaveCriticalSection( &freetype_cs );
4781 return GDI_ERROR;
4784 if(!needsTransform) {
4785 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4786 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4787 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4789 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4790 bottom = (ft_face->glyph->metrics.horiBearingY -
4791 ft_face->glyph->metrics.height) & -64;
4792 lpgm->gmCellIncX = adv;
4793 lpgm->gmCellIncY = 0;
4794 } else {
4795 INT xc, yc;
4796 FT_Vector vec;
4798 left = right = 0;
4800 for(xc = 0; xc < 2; xc++) {
4801 for(yc = 0; yc < 2; yc++) {
4802 vec.x = (ft_face->glyph->metrics.horiBearingX +
4803 xc * ft_face->glyph->metrics.width);
4804 vec.y = ft_face->glyph->metrics.horiBearingY -
4805 yc * ft_face->glyph->metrics.height;
4806 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4807 pFT_Vector_Transform(&vec, &transMat);
4808 if(xc == 0 && yc == 0) {
4809 left = right = vec.x;
4810 top = bottom = vec.y;
4811 } else {
4812 if(vec.x < left) left = vec.x;
4813 else if(vec.x > right) right = vec.x;
4814 if(vec.y < bottom) bottom = vec.y;
4815 else if(vec.y > top) top = vec.y;
4819 left = left & -64;
4820 right = (right + 63) & -64;
4821 bottom = bottom & -64;
4822 top = (top + 63) & -64;
4824 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4825 vec.x = ft_face->glyph->metrics.horiAdvance;
4826 vec.y = 0;
4827 pFT_Vector_Transform(&vec, &transMat);
4828 lpgm->gmCellIncX = (vec.x+63) >> 6;
4829 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4831 vec.x = ft_face->glyph->metrics.horiAdvance;
4832 vec.y = 0;
4833 pFT_Vector_Transform(&vec, &transMatUnrotated);
4834 adv = (vec.x+63) >> 6;
4837 lsb = left >> 6;
4838 bbx = (right - left) >> 6;
4839 lpgm->gmBlackBoxX = (right - left) >> 6;
4840 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4841 lpgm->gmptGlyphOrigin.x = left >> 6;
4842 lpgm->gmptGlyphOrigin.y = top >> 6;
4844 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4845 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4846 lpgm->gmCellIncX, lpgm->gmCellIncY);
4848 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4849 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4851 FONT_GM(font,original_index)->gm = *lpgm;
4852 FONT_GM(font,original_index)->adv = adv;
4853 FONT_GM(font,original_index)->lsb = lsb;
4854 FONT_GM(font,original_index)->bbx = bbx;
4855 FONT_GM(font,original_index)->init = TRUE;
4858 if(format == GGO_METRICS)
4860 LeaveCriticalSection( &freetype_cs );
4861 return 1; /* FIXME */
4864 if(ft_face->glyph->format != ft_glyph_format_outline &&
4865 (format == GGO_NATIVE || format == GGO_BEZIER ||
4866 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4867 format == GGO_GRAY8_BITMAP))
4869 TRACE("loaded a bitmap\n");
4870 LeaveCriticalSection( &freetype_cs );
4871 return GDI_ERROR;
4874 switch(format) {
4875 case GGO_BITMAP:
4876 width = lpgm->gmBlackBoxX;
4877 height = lpgm->gmBlackBoxY;
4878 pitch = ((width + 31) >> 5) << 2;
4879 needed = pitch * height;
4881 if(!buf || !buflen) break;
4883 switch(ft_face->glyph->format) {
4884 case ft_glyph_format_bitmap:
4886 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4887 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4888 INT h = ft_face->glyph->bitmap.rows;
4889 while(h--) {
4890 memcpy(dst, src, w);
4891 src += ft_face->glyph->bitmap.pitch;
4892 dst += pitch;
4894 break;
4897 case ft_glyph_format_outline:
4898 ft_bitmap.width = width;
4899 ft_bitmap.rows = height;
4900 ft_bitmap.pitch = pitch;
4901 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4902 ft_bitmap.buffer = buf;
4904 if(needsTransform)
4905 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4907 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4909 /* Note: FreeType will only set 'black' bits for us. */
4910 memset(buf, 0, needed);
4911 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4912 break;
4914 default:
4915 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4916 LeaveCriticalSection( &freetype_cs );
4917 return GDI_ERROR;
4919 break;
4921 case GGO_GRAY2_BITMAP:
4922 case GGO_GRAY4_BITMAP:
4923 case GGO_GRAY8_BITMAP:
4924 case WINE_GGO_GRAY16_BITMAP:
4926 unsigned int mult, row, col;
4927 BYTE *start, *ptr;
4929 width = lpgm->gmBlackBoxX;
4930 height = lpgm->gmBlackBoxY;
4931 pitch = (width + 3) / 4 * 4;
4932 needed = pitch * height;
4934 if(!buf || !buflen) break;
4936 switch(ft_face->glyph->format) {
4937 case ft_glyph_format_bitmap:
4939 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4940 INT h = ft_face->glyph->bitmap.rows;
4941 INT x;
4942 memset( buf, 0, needed );
4943 while(h--) {
4944 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4945 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4946 src += ft_face->glyph->bitmap.pitch;
4947 dst += pitch;
4949 LeaveCriticalSection( &freetype_cs );
4950 return needed;
4952 case ft_glyph_format_outline:
4954 ft_bitmap.width = width;
4955 ft_bitmap.rows = height;
4956 ft_bitmap.pitch = pitch;
4957 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4958 ft_bitmap.buffer = buf;
4960 if(needsTransform)
4961 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4963 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4965 memset(ft_bitmap.buffer, 0, buflen);
4967 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4969 if(format == GGO_GRAY2_BITMAP)
4970 mult = 4;
4971 else if(format == GGO_GRAY4_BITMAP)
4972 mult = 16;
4973 else if(format == GGO_GRAY8_BITMAP)
4974 mult = 64;
4975 else /* format == WINE_GGO_GRAY16_BITMAP */
4977 LeaveCriticalSection( &freetype_cs );
4978 return needed;
4980 break;
4982 default:
4983 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4984 LeaveCriticalSection( &freetype_cs );
4985 return GDI_ERROR;
4988 start = buf;
4989 for(row = 0; row < height; row++) {
4990 ptr = start;
4991 for(col = 0; col < width; col++, ptr++) {
4992 *ptr = (((int)*ptr) * mult + 128) / 256;
4994 start += pitch;
4996 break;
4999 case WINE_GGO_HRGB_BITMAP:
5000 case WINE_GGO_HBGR_BITMAP:
5001 case WINE_GGO_VRGB_BITMAP:
5002 case WINE_GGO_VBGR_BITMAP:
5003 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5005 switch (ft_face->glyph->format)
5007 case FT_GLYPH_FORMAT_BITMAP:
5009 BYTE *src, *dst;
5010 INT src_pitch, x;
5012 width = lpgm->gmBlackBoxX;
5013 height = lpgm->gmBlackBoxY;
5014 pitch = width * 4;
5015 needed = pitch * height;
5017 if (!buf || !buflen) break;
5019 memset(buf, 0, buflen);
5020 dst = buf;
5021 src = ft_face->glyph->bitmap.buffer;
5022 src_pitch = ft_face->glyph->bitmap.pitch;
5024 height = min( height, ft_face->glyph->bitmap.rows );
5025 while ( height-- )
5027 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5029 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5030 ((unsigned int *)dst)[x] = ~0u;
5032 src += src_pitch;
5033 dst += pitch;
5036 break;
5039 case FT_GLYPH_FORMAT_OUTLINE:
5041 unsigned int *dst;
5042 BYTE *src;
5043 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5044 INT x_shift, y_shift;
5045 BOOL rgb;
5046 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5047 FT_Render_Mode render_mode =
5048 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5049 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5051 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5053 if ( render_mode == FT_RENDER_MODE_LCD)
5055 lpgm->gmBlackBoxX += 2;
5056 lpgm->gmptGlyphOrigin.x -= 1;
5058 else
5060 lpgm->gmBlackBoxY += 2;
5061 lpgm->gmptGlyphOrigin.y += 1;
5065 width = lpgm->gmBlackBoxX;
5066 height = lpgm->gmBlackBoxY;
5067 pitch = width * 4;
5068 needed = pitch * height;
5070 if (!buf || !buflen) break;
5072 memset(buf, 0, buflen);
5073 dst = buf;
5074 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5076 if ( needsTransform )
5077 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5079 if ( pFT_Library_SetLcdFilter )
5080 pFT_Library_SetLcdFilter( library, lcdfilter );
5081 pFT_Render_Glyph (ft_face->glyph, render_mode);
5083 src = ft_face->glyph->bitmap.buffer;
5084 src_pitch = ft_face->glyph->bitmap.pitch;
5085 src_width = ft_face->glyph->bitmap.width;
5086 src_height = ft_face->glyph->bitmap.rows;
5088 if ( render_mode == FT_RENDER_MODE_LCD)
5090 rgb_interval = 1;
5091 hmul = 3;
5092 vmul = 1;
5094 else
5096 rgb_interval = src_pitch;
5097 hmul = 1;
5098 vmul = 3;
5101 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5102 if ( x_shift < 0 ) x_shift = 0;
5103 if ( x_shift + (src_width / hmul) > width )
5104 x_shift = width - (src_width / hmul);
5106 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5107 if ( y_shift < 0 ) y_shift = 0;
5108 if ( y_shift + (src_height / vmul) > height )
5109 y_shift = height - (src_height / vmul);
5111 dst += x_shift + y_shift * ( pitch / 4 );
5112 while ( src_height )
5114 for ( x = 0; x < src_width / hmul; x++ )
5116 if ( rgb )
5118 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5119 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5120 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5121 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5123 else
5125 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5126 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5127 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5128 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5131 src += src_pitch * vmul;
5132 dst += pitch / 4;
5133 src_height -= vmul;
5136 break;
5139 default:
5140 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5141 LeaveCriticalSection ( &freetype_cs );
5142 return GDI_ERROR;
5145 break;
5147 #else
5148 LeaveCriticalSection( &freetype_cs );
5149 return GDI_ERROR;
5150 #endif
5152 case GGO_NATIVE:
5154 int contour, point = 0, first_pt;
5155 FT_Outline *outline = &ft_face->glyph->outline;
5156 TTPOLYGONHEADER *pph;
5157 TTPOLYCURVE *ppc;
5158 DWORD pph_start, cpfx, type;
5160 if(buflen == 0) buf = NULL;
5162 if (needsTransform && buf) {
5163 pFT_Outline_Transform(outline, &transMat);
5166 for(contour = 0; contour < outline->n_contours; contour++) {
5167 pph_start = needed;
5168 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5169 first_pt = point;
5170 if(buf) {
5171 pph->dwType = TT_POLYGON_TYPE;
5172 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5174 needed += sizeof(*pph);
5175 point++;
5176 while(point <= outline->contours[contour]) {
5177 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5178 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5179 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5180 cpfx = 0;
5181 do {
5182 if(buf)
5183 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5184 cpfx++;
5185 point++;
5186 } while(point <= outline->contours[contour] &&
5187 (outline->tags[point] & FT_Curve_Tag_On) ==
5188 (outline->tags[point-1] & FT_Curve_Tag_On));
5189 /* At the end of a contour Windows adds the start point, but
5190 only for Beziers */
5191 if(point > outline->contours[contour] &&
5192 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5193 if(buf)
5194 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5195 cpfx++;
5196 } else if(point <= outline->contours[contour] &&
5197 outline->tags[point] & FT_Curve_Tag_On) {
5198 /* add closing pt for bezier */
5199 if(buf)
5200 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5201 cpfx++;
5202 point++;
5204 if(buf) {
5205 ppc->wType = type;
5206 ppc->cpfx = cpfx;
5208 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5210 if(buf)
5211 pph->cb = needed - pph_start;
5213 break;
5215 case GGO_BEZIER:
5217 /* Convert the quadratic Beziers to cubic Beziers.
5218 The parametric eqn for a cubic Bezier is, from PLRM:
5219 r(t) = at^3 + bt^2 + ct + r0
5220 with the control points:
5221 r1 = r0 + c/3
5222 r2 = r1 + (c + b)/3
5223 r3 = r0 + c + b + a
5225 A quadratic Beizer has the form:
5226 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5228 So equating powers of t leads to:
5229 r1 = 2/3 p1 + 1/3 p0
5230 r2 = 2/3 p1 + 1/3 p2
5231 and of course r0 = p0, r3 = p2
5234 int contour, point = 0, first_pt;
5235 FT_Outline *outline = &ft_face->glyph->outline;
5236 TTPOLYGONHEADER *pph;
5237 TTPOLYCURVE *ppc;
5238 DWORD pph_start, cpfx, type;
5239 FT_Vector cubic_control[4];
5240 if(buflen == 0) buf = NULL;
5242 if (needsTransform && buf) {
5243 pFT_Outline_Transform(outline, &transMat);
5246 for(contour = 0; contour < outline->n_contours; contour++) {
5247 pph_start = needed;
5248 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5249 first_pt = point;
5250 if(buf) {
5251 pph->dwType = TT_POLYGON_TYPE;
5252 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5254 needed += sizeof(*pph);
5255 point++;
5256 while(point <= outline->contours[contour]) {
5257 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5258 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5259 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5260 cpfx = 0;
5261 do {
5262 if(type == TT_PRIM_LINE) {
5263 if(buf)
5264 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5265 cpfx++;
5266 point++;
5267 } else {
5268 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5269 so cpfx = 3n */
5271 /* FIXME: Possible optimization in endpoint calculation
5272 if there are two consecutive curves */
5273 cubic_control[0] = outline->points[point-1];
5274 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5275 cubic_control[0].x += outline->points[point].x + 1;
5276 cubic_control[0].y += outline->points[point].y + 1;
5277 cubic_control[0].x >>= 1;
5278 cubic_control[0].y >>= 1;
5280 if(point+1 > outline->contours[contour])
5281 cubic_control[3] = outline->points[first_pt];
5282 else {
5283 cubic_control[3] = outline->points[point+1];
5284 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5285 cubic_control[3].x += outline->points[point].x + 1;
5286 cubic_control[3].y += outline->points[point].y + 1;
5287 cubic_control[3].x >>= 1;
5288 cubic_control[3].y >>= 1;
5291 /* r1 = 1/3 p0 + 2/3 p1
5292 r2 = 1/3 p2 + 2/3 p1 */
5293 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5294 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5295 cubic_control[2] = cubic_control[1];
5296 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5297 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5298 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5299 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5300 if(buf) {
5301 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5302 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5303 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5305 cpfx += 3;
5306 point++;
5308 } while(point <= outline->contours[contour] &&
5309 (outline->tags[point] & FT_Curve_Tag_On) ==
5310 (outline->tags[point-1] & FT_Curve_Tag_On));
5311 /* At the end of a contour Windows adds the start point,
5312 but only for Beziers and we've already done that.
5314 if(point <= outline->contours[contour] &&
5315 outline->tags[point] & FT_Curve_Tag_On) {
5316 /* This is the closing pt of a bezier, but we've already
5317 added it, so just inc point and carry on */
5318 point++;
5320 if(buf) {
5321 ppc->wType = type;
5322 ppc->cpfx = cpfx;
5324 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5326 if(buf)
5327 pph->cb = needed - pph_start;
5329 break;
5332 default:
5333 FIXME("Unsupported format %d\n", format);
5334 LeaveCriticalSection( &freetype_cs );
5335 return GDI_ERROR;
5337 LeaveCriticalSection( &freetype_cs );
5338 return needed;
5341 static BOOL get_bitmap_text_metrics(GdiFont *font)
5343 FT_Face ft_face = font->ft_face;
5344 #ifdef HAVE_FREETYPE_FTWINFNT_H
5345 FT_WinFNT_HeaderRec winfnt_header;
5346 #endif
5347 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5348 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5349 font->potm->otmSize = size;
5351 #define TM font->potm->otmTextMetrics
5352 #ifdef HAVE_FREETYPE_FTWINFNT_H
5353 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5355 TM.tmHeight = winfnt_header.pixel_height;
5356 TM.tmAscent = winfnt_header.ascent;
5357 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5358 TM.tmInternalLeading = winfnt_header.internal_leading;
5359 TM.tmExternalLeading = winfnt_header.external_leading;
5360 TM.tmAveCharWidth = winfnt_header.avg_width;
5361 TM.tmMaxCharWidth = winfnt_header.max_width;
5362 TM.tmWeight = winfnt_header.weight;
5363 TM.tmOverhang = 0;
5364 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5365 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5366 TM.tmFirstChar = winfnt_header.first_char;
5367 TM.tmLastChar = winfnt_header.last_char;
5368 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5369 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5370 TM.tmItalic = winfnt_header.italic;
5371 TM.tmUnderlined = font->underline;
5372 TM.tmStruckOut = font->strikeout;
5373 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5374 TM.tmCharSet = winfnt_header.charset;
5376 else
5377 #endif
5379 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5380 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5381 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5382 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5383 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5384 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5385 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5386 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5387 TM.tmOverhang = 0;
5388 TM.tmDigitizedAspectX = 96; /* FIXME */
5389 TM.tmDigitizedAspectY = 96; /* FIXME */
5390 TM.tmFirstChar = 1;
5391 TM.tmLastChar = 255;
5392 TM.tmDefaultChar = 32;
5393 TM.tmBreakChar = 32;
5394 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5395 TM.tmUnderlined = font->underline;
5396 TM.tmStruckOut = font->strikeout;
5397 /* NB inverted meaning of TMPF_FIXED_PITCH */
5398 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5399 TM.tmCharSet = font->charset;
5401 #undef TM
5403 return TRUE;
5407 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5409 double scale_x, scale_y;
5411 if (font->aveWidth)
5413 scale_x = (double)font->aveWidth;
5414 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5416 else
5417 scale_x = font->scale_y;
5419 scale_x *= fabs(font->font_desc.matrix.eM11);
5420 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5422 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5423 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5425 SCALE_Y(ptm->tmHeight);
5426 SCALE_Y(ptm->tmAscent);
5427 SCALE_Y(ptm->tmDescent);
5428 SCALE_Y(ptm->tmInternalLeading);
5429 SCALE_Y(ptm->tmExternalLeading);
5430 SCALE_Y(ptm->tmOverhang);
5432 SCALE_X(ptm->tmAveCharWidth);
5433 SCALE_X(ptm->tmMaxCharWidth);
5435 #undef SCALE_X
5436 #undef SCALE_Y
5439 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5441 double scale_x, scale_y;
5443 if (font->aveWidth)
5445 scale_x = (double)font->aveWidth;
5446 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5448 else
5449 scale_x = font->scale_y;
5451 scale_x *= fabs(font->font_desc.matrix.eM11);
5452 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5454 scale_font_metrics(font, &potm->otmTextMetrics);
5456 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5457 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5459 SCALE_Y(potm->otmAscent);
5460 SCALE_Y(potm->otmDescent);
5461 SCALE_Y(potm->otmLineGap);
5462 SCALE_Y(potm->otmsCapEmHeight);
5463 SCALE_Y(potm->otmsXHeight);
5464 SCALE_Y(potm->otmrcFontBox.top);
5465 SCALE_Y(potm->otmrcFontBox.bottom);
5466 SCALE_X(potm->otmrcFontBox.left);
5467 SCALE_X(potm->otmrcFontBox.right);
5468 SCALE_Y(potm->otmMacAscent);
5469 SCALE_Y(potm->otmMacDescent);
5470 SCALE_Y(potm->otmMacLineGap);
5471 SCALE_X(potm->otmptSubscriptSize.x);
5472 SCALE_Y(potm->otmptSubscriptSize.y);
5473 SCALE_X(potm->otmptSubscriptOffset.x);
5474 SCALE_Y(potm->otmptSubscriptOffset.y);
5475 SCALE_X(potm->otmptSuperscriptSize.x);
5476 SCALE_Y(potm->otmptSuperscriptSize.y);
5477 SCALE_X(potm->otmptSuperscriptOffset.x);
5478 SCALE_Y(potm->otmptSuperscriptOffset.y);
5479 SCALE_Y(potm->otmsStrikeoutSize);
5480 SCALE_Y(potm->otmsStrikeoutPosition);
5481 SCALE_Y(potm->otmsUnderscoreSize);
5482 SCALE_Y(potm->otmsUnderscorePosition);
5484 #undef SCALE_X
5485 #undef SCALE_Y
5488 /*************************************************************
5489 * WineEngGetTextMetrics
5492 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5494 GDI_CheckNotLock();
5495 EnterCriticalSection( &freetype_cs );
5496 if(!font->potm) {
5497 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5498 if(!get_bitmap_text_metrics(font))
5500 LeaveCriticalSection( &freetype_cs );
5501 return FALSE;
5504 /* Make sure that the font has sane width/height ratio */
5505 if (font->aveWidth)
5507 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5509 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5510 font->aveWidth = 0;
5515 *ptm = font->potm->otmTextMetrics;
5516 scale_font_metrics(font, ptm);
5517 LeaveCriticalSection( &freetype_cs );
5518 return TRUE;
5521 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5523 int i;
5525 for(i = 0; i < ft_face->num_charmaps; i++)
5527 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5528 return TRUE;
5530 return FALSE;
5533 /*************************************************************
5534 * WineEngGetOutlineTextMetrics
5537 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5538 OUTLINETEXTMETRICW *potm)
5540 FT_Face ft_face = font->ft_face;
5541 UINT needed, lenfam, lensty, ret;
5542 TT_OS2 *pOS2;
5543 TT_HoriHeader *pHori;
5544 TT_Postscript *pPost;
5545 FT_Fixed x_scale, y_scale;
5546 WCHAR *family_nameW, *style_nameW;
5547 static const WCHAR spaceW[] = {' ', '\0'};
5548 char *cp;
5549 INT ascent, descent;
5551 TRACE("font=%p\n", font);
5553 if(!FT_IS_SCALABLE(ft_face))
5554 return 0;
5556 GDI_CheckNotLock();
5557 EnterCriticalSection( &freetype_cs );
5559 if(font->potm) {
5560 if(cbSize >= font->potm->otmSize)
5562 memcpy(potm, font->potm, font->potm->otmSize);
5563 scale_outline_font_metrics(font, potm);
5565 LeaveCriticalSection( &freetype_cs );
5566 return font->potm->otmSize;
5570 needed = sizeof(*potm);
5572 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5573 family_nameW = strdupW(font->name);
5575 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5576 * sizeof(WCHAR);
5577 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5578 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5579 style_nameW, lensty/sizeof(WCHAR));
5581 /* These names should be read from the TT name table */
5583 /* length of otmpFamilyName */
5584 needed += lenfam;
5586 /* length of otmpFaceName */
5587 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5588 needed += lenfam; /* just the family name */
5589 } else {
5590 needed += lenfam + lensty; /* family + " " + style */
5593 /* length of otmpStyleName */
5594 needed += lensty;
5596 /* length of otmpFullName */
5597 needed += lenfam + lensty;
5600 x_scale = ft_face->size->metrics.x_scale;
5601 y_scale = ft_face->size->metrics.y_scale;
5603 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5604 if(!pOS2) {
5605 FIXME("Can't find OS/2 table - not TT font?\n");
5606 ret = 0;
5607 goto end;
5610 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5611 if(!pHori) {
5612 FIXME("Can't find HHEA table - not TT font?\n");
5613 ret = 0;
5614 goto end;
5617 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5619 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",
5620 pOS2->usWinAscent, pOS2->usWinDescent,
5621 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5622 ft_face->ascender, ft_face->descender, ft_face->height,
5623 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5624 ft_face->bbox.yMax, ft_face->bbox.yMin);
5626 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5627 font->potm->otmSize = needed;
5629 #define TM font->potm->otmTextMetrics
5631 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5632 ascent = pHori->Ascender;
5633 descent = -pHori->Descender;
5634 } else {
5635 ascent = pOS2->usWinAscent;
5636 descent = pOS2->usWinDescent;
5639 if(font->yMax) {
5640 TM.tmAscent = font->yMax;
5641 TM.tmDescent = -font->yMin;
5642 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5643 } else {
5644 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5645 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5646 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5647 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5650 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5652 /* MSDN says:
5653 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5655 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5656 ((ascent + descent) -
5657 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5659 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5660 if (TM.tmAveCharWidth == 0) {
5661 TM.tmAveCharWidth = 1;
5663 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5664 TM.tmWeight = FW_REGULAR;
5665 if (font->fake_bold)
5666 TM.tmWeight = FW_BOLD;
5667 else
5669 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5671 if (pOS2->usWeightClass > FW_MEDIUM)
5672 TM.tmWeight = pOS2->usWeightClass;
5674 else if (pOS2->usWeightClass <= FW_MEDIUM)
5675 TM.tmWeight = pOS2->usWeightClass;
5677 TM.tmOverhang = 0;
5678 TM.tmDigitizedAspectX = 300;
5679 TM.tmDigitizedAspectY = 300;
5680 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5681 * symbol range to 0 - f0ff
5684 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5686 TM.tmFirstChar = 0;
5687 switch(GetACP())
5689 case 1257: /* Baltic */
5690 TM.tmLastChar = 0xf8fd;
5691 break;
5692 default:
5693 TM.tmLastChar = 0xf0ff;
5695 TM.tmBreakChar = 0x20;
5696 TM.tmDefaultChar = 0x1f;
5698 else
5700 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5701 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5703 if(pOS2->usFirstCharIndex <= 1)
5704 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5705 else if (pOS2->usFirstCharIndex > 0xff)
5706 TM.tmBreakChar = 0x20;
5707 else
5708 TM.tmBreakChar = pOS2->usFirstCharIndex;
5709 TM.tmDefaultChar = TM.tmBreakChar - 1;
5711 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5712 TM.tmUnderlined = font->underline;
5713 TM.tmStruckOut = font->strikeout;
5715 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5716 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5717 (pOS2->version == 0xFFFFU ||
5718 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5719 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5720 else
5721 TM.tmPitchAndFamily = 0;
5723 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5725 case PAN_FAMILY_SCRIPT:
5726 TM.tmPitchAndFamily |= FF_SCRIPT;
5727 break;
5729 case PAN_FAMILY_DECORATIVE:
5730 TM.tmPitchAndFamily |= FF_DECORATIVE;
5731 break;
5733 case PAN_ANY:
5734 case PAN_NO_FIT:
5735 case PAN_FAMILY_TEXT_DISPLAY:
5736 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5737 /* which is clearly not what the panose spec says. */
5738 default:
5739 if(TM.tmPitchAndFamily == 0 || /* fixed */
5740 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5741 TM.tmPitchAndFamily = FF_MODERN;
5742 else
5744 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5746 case PAN_ANY:
5747 case PAN_NO_FIT:
5748 default:
5749 TM.tmPitchAndFamily |= FF_DONTCARE;
5750 break;
5752 case PAN_SERIF_COVE:
5753 case PAN_SERIF_OBTUSE_COVE:
5754 case PAN_SERIF_SQUARE_COVE:
5755 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5756 case PAN_SERIF_SQUARE:
5757 case PAN_SERIF_THIN:
5758 case PAN_SERIF_BONE:
5759 case PAN_SERIF_EXAGGERATED:
5760 case PAN_SERIF_TRIANGLE:
5761 TM.tmPitchAndFamily |= FF_ROMAN;
5762 break;
5764 case PAN_SERIF_NORMAL_SANS:
5765 case PAN_SERIF_OBTUSE_SANS:
5766 case PAN_SERIF_PERP_SANS:
5767 case PAN_SERIF_FLARED:
5768 case PAN_SERIF_ROUNDED:
5769 TM.tmPitchAndFamily |= FF_SWISS;
5770 break;
5773 break;
5776 if(FT_IS_SCALABLE(ft_face))
5777 TM.tmPitchAndFamily |= TMPF_VECTOR;
5779 if(FT_IS_SFNT(ft_face))
5781 if (font->ntmFlags & NTM_PS_OPENTYPE)
5782 TM.tmPitchAndFamily |= TMPF_DEVICE;
5783 else
5784 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5787 TM.tmCharSet = font->charset;
5789 font->potm->otmFiller = 0;
5790 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5791 font->potm->otmfsSelection = pOS2->fsSelection;
5792 font->potm->otmfsType = pOS2->fsType;
5793 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5794 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5795 font->potm->otmItalicAngle = 0; /* POST table */
5796 font->potm->otmEMSquare = ft_face->units_per_EM;
5797 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5798 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5799 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5800 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5801 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5802 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5803 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5804 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5805 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5806 font->potm->otmMacAscent = TM.tmAscent;
5807 font->potm->otmMacDescent = -TM.tmDescent;
5808 font->potm->otmMacLineGap = font->potm->otmLineGap;
5809 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5810 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5811 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5812 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5813 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5814 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5815 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5816 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5817 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5818 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5819 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5820 if(!pPost) {
5821 font->potm->otmsUnderscoreSize = 0;
5822 font->potm->otmsUnderscorePosition = 0;
5823 } else {
5824 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5825 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5827 #undef TM
5829 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5830 cp = (char*)font->potm + sizeof(*font->potm);
5831 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5832 strcpyW((WCHAR*)cp, family_nameW);
5833 cp += lenfam;
5834 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5835 strcpyW((WCHAR*)cp, style_nameW);
5836 cp += lensty;
5837 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5838 strcpyW((WCHAR*)cp, family_nameW);
5839 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5840 strcatW((WCHAR*)cp, spaceW);
5841 strcatW((WCHAR*)cp, style_nameW);
5842 cp += lenfam + lensty;
5843 } else
5844 cp += lenfam;
5845 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5846 strcpyW((WCHAR*)cp, family_nameW);
5847 strcatW((WCHAR*)cp, spaceW);
5848 strcatW((WCHAR*)cp, style_nameW);
5849 ret = needed;
5851 if(potm && needed <= cbSize)
5853 memcpy(potm, font->potm, font->potm->otmSize);
5854 scale_outline_font_metrics(font, potm);
5857 end:
5858 HeapFree(GetProcessHeap(), 0, style_nameW);
5859 HeapFree(GetProcessHeap(), 0, family_nameW);
5861 LeaveCriticalSection( &freetype_cs );
5862 return ret;
5865 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5867 HFONTLIST *hfontlist;
5868 child->font = alloc_font();
5869 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5870 if(!child->font->ft_face)
5872 free_font(child->font);
5873 child->font = NULL;
5874 return FALSE;
5877 child->font->font_desc = font->font_desc;
5878 child->font->ntmFlags = child->face->ntmFlags;
5879 child->font->orientation = font->orientation;
5880 child->font->scale_y = font->scale_y;
5881 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5882 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5883 child->font->name = strdupW(child->face->family->FamilyName);
5884 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5885 child->font->base_font = font;
5886 list_add_head(&child_font_list, &child->font->entry);
5887 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5888 return TRUE;
5891 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5893 FT_UInt g;
5894 CHILD_FONT *child_font;
5896 if(font->base_font)
5897 font = font->base_font;
5899 *linked_font = font;
5901 if((*glyph = get_glyph_index(font, c)))
5902 return TRUE;
5904 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5906 if(!child_font->font)
5907 if(!load_child_font(font, child_font))
5908 continue;
5910 if(!child_font->font->ft_face)
5911 continue;
5912 g = get_glyph_index(child_font->font, c);
5913 if(g)
5915 *glyph = g;
5916 *linked_font = child_font->font;
5917 return TRUE;
5920 return FALSE;
5923 /*************************************************************
5924 * WineEngGetCharWidth
5927 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5928 LPINT buffer)
5930 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5931 UINT c;
5932 GLYPHMETRICS gm;
5933 FT_UInt glyph_index;
5934 GdiFont *linked_font;
5936 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5938 GDI_CheckNotLock();
5939 EnterCriticalSection( &freetype_cs );
5940 for(c = firstChar; c <= lastChar; c++) {
5941 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5942 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5943 &gm, 0, NULL, &identity);
5944 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5946 LeaveCriticalSection( &freetype_cs );
5947 return TRUE;
5950 /*************************************************************
5951 * WineEngGetCharABCWidths
5954 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5955 LPABC buffer)
5957 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5958 UINT c;
5959 GLYPHMETRICS gm;
5960 FT_UInt glyph_index;
5961 GdiFont *linked_font;
5963 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5965 if(!FT_IS_SCALABLE(font->ft_face))
5966 return FALSE;
5968 GDI_CheckNotLock();
5969 EnterCriticalSection( &freetype_cs );
5971 for(c = firstChar; c <= lastChar; c++) {
5972 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5973 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5974 &gm, 0, NULL, &identity);
5975 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5976 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5977 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5978 FONT_GM(linked_font,glyph_index)->bbx;
5980 LeaveCriticalSection( &freetype_cs );
5981 return TRUE;
5984 /*************************************************************
5985 * WineEngGetCharABCWidthsFloat
5988 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
5990 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
5991 UINT c;
5992 GLYPHMETRICS gm;
5993 FT_UInt glyph_index;
5994 GdiFont *linked_font;
5996 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
5998 GDI_CheckNotLock();
5999 EnterCriticalSection( &freetype_cs );
6001 for (c = first; c <= last; c++)
6003 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6004 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6005 &gm, 0, NULL, &identity);
6006 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6007 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6008 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6009 FONT_GM(linked_font, glyph_index)->lsb -
6010 FONT_GM(linked_font, glyph_index)->bbx;
6012 LeaveCriticalSection( &freetype_cs );
6013 return TRUE;
6016 /*************************************************************
6017 * WineEngGetCharABCWidthsI
6020 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6021 LPABC buffer)
6023 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6024 UINT c;
6025 GLYPHMETRICS gm;
6026 FT_UInt glyph_index;
6027 GdiFont *linked_font;
6029 if(!FT_HAS_HORIZONTAL(font->ft_face))
6030 return FALSE;
6032 GDI_CheckNotLock();
6033 EnterCriticalSection( &freetype_cs );
6035 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6036 if (!pgi)
6037 for(c = firstChar; c < firstChar+count; c++) {
6038 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6039 &gm, 0, NULL, &identity);
6040 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6041 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6042 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6043 - FONT_GM(linked_font,c)->bbx;
6045 else
6046 for(c = 0; c < count; c++) {
6047 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6048 &gm, 0, NULL, &identity);
6049 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6050 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6051 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6052 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6055 LeaveCriticalSection( &freetype_cs );
6056 return TRUE;
6059 /*************************************************************
6060 * WineEngGetTextExtentExPoint
6063 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6064 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6066 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6067 INT idx;
6068 INT nfit = 0, ext;
6069 GLYPHMETRICS gm;
6070 TEXTMETRICW tm;
6071 FT_UInt glyph_index;
6072 GdiFont *linked_font;
6074 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6075 max_ext, size);
6077 GDI_CheckNotLock();
6078 EnterCriticalSection( &freetype_cs );
6080 size->cx = 0;
6081 WineEngGetTextMetrics(font, &tm);
6082 size->cy = tm.tmHeight;
6084 for(idx = 0; idx < count; idx++) {
6085 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6086 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6087 &gm, 0, NULL, &identity);
6088 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6089 ext = size->cx;
6090 if (! pnfit || ext <= max_ext) {
6091 ++nfit;
6092 if (dxs)
6093 dxs[idx] = ext;
6097 if (pnfit)
6098 *pnfit = nfit;
6100 LeaveCriticalSection( &freetype_cs );
6101 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6102 return TRUE;
6105 /*************************************************************
6106 * WineEngGetTextExtentExPointI
6109 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6110 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6112 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6113 INT idx;
6114 INT nfit = 0, ext;
6115 GLYPHMETRICS gm;
6116 TEXTMETRICW tm;
6118 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6120 GDI_CheckNotLock();
6121 EnterCriticalSection( &freetype_cs );
6123 size->cx = 0;
6124 WineEngGetTextMetrics(font, &tm);
6125 size->cy = tm.tmHeight;
6127 for(idx = 0; idx < count; idx++) {
6128 WineEngGetGlyphOutline(font, indices[idx],
6129 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6130 &identity);
6131 size->cx += FONT_GM(font,indices[idx])->adv;
6132 ext = size->cx;
6133 if (! pnfit || ext <= max_ext) {
6134 ++nfit;
6135 if (dxs)
6136 dxs[idx] = ext;
6140 if (pnfit)
6141 *pnfit = nfit;
6143 LeaveCriticalSection( &freetype_cs );
6144 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6145 return TRUE;
6148 /*************************************************************
6149 * WineEngGetFontData
6152 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6153 DWORD cbData)
6155 FT_Face ft_face = font->ft_face;
6156 FT_ULong len;
6157 FT_Error err;
6159 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6160 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6161 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6163 if(!FT_IS_SFNT(ft_face))
6164 return GDI_ERROR;
6166 if(!buf || !cbData)
6167 len = 0;
6168 else
6169 len = cbData;
6171 if(table) { /* MS tags differ in endianness from FT ones */
6172 table = table >> 24 | table << 24 |
6173 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6176 /* make sure value of len is the value freetype says it needs */
6177 if(buf && len)
6179 FT_ULong needed = 0;
6180 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6181 if( !err && needed < len) len = needed;
6183 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6185 if(err) {
6186 TRACE("Can't find table %c%c%c%c\n",
6187 /* bytes were reversed */
6188 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6189 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6190 return GDI_ERROR;
6192 return len;
6195 /*************************************************************
6196 * WineEngGetTextFace
6199 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6201 INT n = strlenW(font->name) + 1;
6202 if(str) {
6203 lstrcpynW(str, font->name, count);
6204 return min(count, n);
6205 } else
6206 return n;
6209 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6211 if (fs) *fs = font->fs;
6212 return font->charset;
6215 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6217 GdiFont *font = dc->gdiFont, *linked_font;
6218 struct list *first_hfont;
6219 BOOL ret;
6221 GDI_CheckNotLock();
6222 EnterCriticalSection( &freetype_cs );
6223 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6224 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6225 if(font == linked_font)
6226 *new_hfont = dc->hFont;
6227 else
6229 first_hfont = list_head(&linked_font->hfontlist);
6230 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6232 LeaveCriticalSection( &freetype_cs );
6233 return ret;
6236 /* Retrieve a list of supported Unicode ranges for a given font.
6237 * Can be called with NULL gs to calculate the buffer size. Returns
6238 * the number of ranges found.
6240 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6242 DWORD num_ranges = 0;
6244 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6246 FT_UInt glyph_code;
6247 FT_ULong char_code, char_code_prev;
6249 glyph_code = 0;
6250 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6252 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6253 face->num_glyphs, glyph_code, char_code);
6255 if (!glyph_code) return 0;
6257 if (gs)
6259 gs->ranges[0].wcLow = (USHORT)char_code;
6260 gs->ranges[0].cGlyphs = 0;
6261 gs->cGlyphsSupported = 0;
6264 num_ranges = 1;
6265 while (glyph_code)
6267 if (char_code < char_code_prev)
6269 ERR("expected increasing char code from FT_Get_Next_Char\n");
6270 return 0;
6272 if (char_code - char_code_prev > 1)
6274 num_ranges++;
6275 if (gs)
6277 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6278 gs->ranges[num_ranges - 1].cGlyphs = 1;
6279 gs->cGlyphsSupported++;
6282 else if (gs)
6284 gs->ranges[num_ranges - 1].cGlyphs++;
6285 gs->cGlyphsSupported++;
6287 char_code_prev = char_code;
6288 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6291 else
6292 FIXME("encoding %u not supported\n", face->charmap->encoding);
6294 return num_ranges;
6297 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6299 DWORD size = 0;
6300 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6302 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6303 if (glyphset)
6305 glyphset->cbThis = size;
6306 glyphset->cRanges = num_ranges;
6307 glyphset->flAccel = 0;
6309 return size;
6312 /*************************************************************
6313 * FontIsLinked
6315 BOOL WineEngFontIsLinked(GdiFont *font)
6317 BOOL ret;
6318 GDI_CheckNotLock();
6319 EnterCriticalSection( &freetype_cs );
6320 ret = !list_empty(&font->child_fonts);
6321 LeaveCriticalSection( &freetype_cs );
6322 return ret;
6325 static BOOL is_hinting_enabled(void)
6327 /* Use the >= 2.2.0 function if available */
6328 if(pFT_Get_TrueType_Engine_Type)
6330 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6331 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6333 #ifdef FT_DRIVER_HAS_HINTER
6334 else
6336 FT_Module mod;
6338 /* otherwise if we've been compiled with < 2.2.0 headers
6339 use the internal macro */
6340 mod = pFT_Get_Module(library, "truetype");
6341 if(mod && FT_DRIVER_HAS_HINTER(mod))
6342 return TRUE;
6344 #endif
6346 return FALSE;
6349 static BOOL is_subpixel_rendering_enabled( void )
6351 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6352 return pFT_Library_SetLcdFilter &&
6353 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6354 #else
6355 return FALSE;
6356 #endif
6359 /*************************************************************************
6360 * GetRasterizerCaps (GDI32.@)
6362 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6364 static int hinting = -1;
6365 static int subpixel = -1;
6367 if(hinting == -1)
6369 hinting = is_hinting_enabled();
6370 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6373 if ( subpixel == -1 )
6375 subpixel = is_subpixel_rendering_enabled();
6376 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6379 lprs->nSize = sizeof(RASTERIZER_STATUS);
6380 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6381 if ( subpixel )
6382 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6383 lprs->nLanguageID = 0;
6384 return TRUE;
6387 /*************************************************************
6388 * WineEngRealizationInfo
6390 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6392 FIXME("(%p, %p): stub!\n", font, info);
6394 info->flags = 1;
6395 if(FT_IS_SCALABLE(font->ft_face))
6396 info->flags |= 2;
6398 info->cache_num = font->cache_num;
6399 info->unknown2 = -1;
6400 return TRUE;
6403 /*************************************************************************
6404 * Kerning support for TrueType fonts
6406 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6408 struct TT_kern_table
6410 USHORT version;
6411 USHORT nTables;
6414 struct TT_kern_subtable
6416 USHORT version;
6417 USHORT length;
6418 union
6420 USHORT word;
6421 struct
6423 USHORT horizontal : 1;
6424 USHORT minimum : 1;
6425 USHORT cross_stream: 1;
6426 USHORT override : 1;
6427 USHORT reserved1 : 4;
6428 USHORT format : 8;
6429 } bits;
6430 } coverage;
6433 struct TT_format0_kern_subtable
6435 USHORT nPairs;
6436 USHORT searchRange;
6437 USHORT entrySelector;
6438 USHORT rangeShift;
6441 struct TT_kern_pair
6443 USHORT left;
6444 USHORT right;
6445 short value;
6448 static DWORD parse_format0_kern_subtable(GdiFont *font,
6449 const struct TT_format0_kern_subtable *tt_f0_ks,
6450 const USHORT *glyph_to_char,
6451 KERNINGPAIR *kern_pair, DWORD cPairs)
6453 USHORT i, nPairs;
6454 const struct TT_kern_pair *tt_kern_pair;
6456 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6458 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6460 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6461 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6462 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6464 if (!kern_pair || !cPairs)
6465 return nPairs;
6467 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6469 nPairs = min(nPairs, cPairs);
6471 for (i = 0; i < nPairs; i++)
6473 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6474 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6475 /* this algorithm appears to better match what Windows does */
6476 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6477 if (kern_pair->iKernAmount < 0)
6479 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6480 kern_pair->iKernAmount -= font->ppem;
6482 else if (kern_pair->iKernAmount > 0)
6484 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6485 kern_pair->iKernAmount += font->ppem;
6487 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6489 TRACE("left %u right %u value %d\n",
6490 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6492 kern_pair++;
6494 TRACE("copied %u entries\n", nPairs);
6495 return nPairs;
6498 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6500 DWORD length;
6501 void *buf;
6502 const struct TT_kern_table *tt_kern_table;
6503 const struct TT_kern_subtable *tt_kern_subtable;
6504 USHORT i, nTables;
6505 USHORT *glyph_to_char;
6507 GDI_CheckNotLock();
6508 EnterCriticalSection( &freetype_cs );
6509 if (font->total_kern_pairs != (DWORD)-1)
6511 if (cPairs && kern_pair)
6513 cPairs = min(cPairs, font->total_kern_pairs);
6514 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6515 LeaveCriticalSection( &freetype_cs );
6516 return cPairs;
6518 LeaveCriticalSection( &freetype_cs );
6519 return font->total_kern_pairs;
6522 font->total_kern_pairs = 0;
6524 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6526 if (length == GDI_ERROR)
6528 TRACE("no kerning data in the font\n");
6529 LeaveCriticalSection( &freetype_cs );
6530 return 0;
6533 buf = HeapAlloc(GetProcessHeap(), 0, length);
6534 if (!buf)
6536 WARN("Out of memory\n");
6537 LeaveCriticalSection( &freetype_cs );
6538 return 0;
6541 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6543 /* build a glyph index to char code map */
6544 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6545 if (!glyph_to_char)
6547 WARN("Out of memory allocating a glyph index to char code map\n");
6548 HeapFree(GetProcessHeap(), 0, buf);
6549 LeaveCriticalSection( &freetype_cs );
6550 return 0;
6553 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6555 FT_UInt glyph_code;
6556 FT_ULong char_code;
6558 glyph_code = 0;
6559 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6561 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6562 font->ft_face->num_glyphs, glyph_code, char_code);
6564 while (glyph_code)
6566 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6568 /* FIXME: This doesn't match what Windows does: it does some fancy
6569 * things with duplicate glyph index to char code mappings, while
6570 * we just avoid overriding existing entries.
6572 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6573 glyph_to_char[glyph_code] = (USHORT)char_code;
6575 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6578 else
6580 ULONG n;
6582 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6583 for (n = 0; n <= 65535; n++)
6584 glyph_to_char[n] = (USHORT)n;
6587 tt_kern_table = buf;
6588 nTables = GET_BE_WORD(tt_kern_table->nTables);
6589 TRACE("version %u, nTables %u\n",
6590 GET_BE_WORD(tt_kern_table->version), nTables);
6592 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6594 for (i = 0; i < nTables; i++)
6596 struct TT_kern_subtable tt_kern_subtable_copy;
6598 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6599 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6600 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6602 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6603 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6604 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6606 /* According to the TrueType specification this is the only format
6607 * that will be properly interpreted by Windows and OS/2
6609 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6611 DWORD new_chunk, old_total = font->total_kern_pairs;
6613 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6614 glyph_to_char, NULL, 0);
6615 font->total_kern_pairs += new_chunk;
6617 if (!font->kern_pairs)
6618 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6619 font->total_kern_pairs * sizeof(*font->kern_pairs));
6620 else
6621 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6622 font->total_kern_pairs * sizeof(*font->kern_pairs));
6624 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6625 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6627 else
6628 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6630 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6633 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6634 HeapFree(GetProcessHeap(), 0, buf);
6636 if (cPairs && kern_pair)
6638 cPairs = min(cPairs, font->total_kern_pairs);
6639 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6640 LeaveCriticalSection( &freetype_cs );
6641 return cPairs;
6643 LeaveCriticalSection( &freetype_cs );
6644 return font->total_kern_pairs;
6647 #else /* HAVE_FREETYPE */
6649 /*************************************************************************/
6651 BOOL WineEngInit(void)
6653 return FALSE;
6655 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6657 return NULL;
6659 BOOL WineEngDestroyFontInstance(HFONT hfont)
6661 return FALSE;
6664 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6666 return 1;
6669 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6670 LPWORD pgi, DWORD flags)
6672 return GDI_ERROR;
6675 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6676 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6677 const MAT2* lpmat)
6679 ERR("called but we don't have FreeType\n");
6680 return GDI_ERROR;
6683 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6685 ERR("called but we don't have FreeType\n");
6686 return FALSE;
6689 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6690 OUTLINETEXTMETRICW *potm)
6692 ERR("called but we don't have FreeType\n");
6693 return 0;
6696 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6697 LPINT buffer)
6699 ERR("called but we don't have FreeType\n");
6700 return FALSE;
6703 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6704 LPABC buffer)
6706 ERR("called but we don't have FreeType\n");
6707 return FALSE;
6710 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6712 ERR("called but we don't have FreeType\n");
6713 return FALSE;
6716 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6717 LPABC buffer)
6719 ERR("called but we don't have FreeType\n");
6720 return FALSE;
6723 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6724 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6726 ERR("called but we don't have FreeType\n");
6727 return FALSE;
6730 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6731 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6733 ERR("called but we don't have FreeType\n");
6734 return FALSE;
6737 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6738 DWORD cbData)
6740 ERR("called but we don't have FreeType\n");
6741 return GDI_ERROR;
6744 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6746 ERR("called but we don't have FreeType\n");
6747 return 0;
6750 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6752 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6753 return 1;
6756 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6758 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6759 return TRUE;
6762 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6764 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6765 return NULL;
6768 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6770 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6771 return DEFAULT_CHARSET;
6774 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6776 return FALSE;
6779 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6781 FIXME("(%p, %p): stub\n", font, glyphset);
6782 return 0;
6785 BOOL WineEngFontIsLinked(GdiFont *font)
6787 return FALSE;
6790 /*************************************************************************
6791 * GetRasterizerCaps (GDI32.@)
6793 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6795 lprs->nSize = sizeof(RASTERIZER_STATUS);
6796 lprs->wFlags = 0;
6797 lprs->nLanguageID = 0;
6798 return TRUE;
6801 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6803 ERR("called but we don't have FreeType\n");
6804 return 0;
6807 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6809 ERR("called but we don't have FreeType\n");
6810 return FALSE;
6813 #endif /* HAVE_FREETYPE */