gdi32: Pass the source/dest visible rectangles to the AlphaBlend driver entry point.
[wine/testsucceed.git] / dlls / gdi32 / freetype.c
blob3b124229ea416fb8fa8b513c68b7c6b05e6acd27
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 WCHAR *FullName;
266 char *file;
267 void *font_data_ptr;
268 DWORD font_data_size;
269 FT_Long face_index;
270 FONTSIGNATURE fs;
271 FONTSIGNATURE fs_links;
272 DWORD ntmFlags;
273 FT_Fixed font_version;
274 BOOL scalable;
275 Bitmap_Size size; /* set if face is a bitmap */
276 BOOL external; /* TRUE if we should manually add this font to the registry */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
280 } Face;
282 typedef struct tagFamily {
283 struct list entry;
284 const WCHAR *FamilyName;
285 struct list faces;
286 } Family;
288 typedef struct {
289 GLYPHMETRICS gm;
290 INT adv; /* These three hold to widths of the unrotated chars */
291 INT lsb;
292 INT bbx;
293 BOOL init;
294 } GM;
296 typedef struct {
297 FLOAT eM11, eM12;
298 FLOAT eM21, eM22;
299 } FMAT2;
301 typedef struct {
302 DWORD hash;
303 LOGFONTW lf;
304 FMAT2 matrix;
305 BOOL can_use_bitmap;
306 } FONT_DESC;
308 typedef struct tagHFONTLIST {
309 struct list entry;
310 HFONT hfont;
311 } HFONTLIST;
313 typedef struct {
314 struct list entry;
315 Face *face;
316 GdiFont *font;
317 } CHILD_FONT;
319 struct tagGdiFont {
320 struct list entry;
321 GM **gm;
322 DWORD gmsize;
323 struct list hfontlist;
324 OUTLINETEXTMETRICW *potm;
325 DWORD total_kern_pairs;
326 KERNINGPAIR *kern_pairs;
327 struct list child_fonts;
329 /* the following members can be accessed without locking, they are never modified after creation */
330 FT_Face ft_face;
331 struct font_mapping *mapping;
332 LPWSTR name;
333 int charset;
334 int codepage;
335 BOOL fake_italic;
336 BOOL fake_bold;
337 BYTE underline;
338 BYTE strikeout;
339 INT orientation;
340 FONT_DESC font_desc;
341 LONG aveWidth, ppem;
342 double scale_y;
343 SHORT yMax;
344 SHORT yMin;
345 DWORD ntmFlags;
346 FONTSIGNATURE fs;
347 GdiFont *base_font;
348 VOID *GSUB_Table;
349 DWORD cache_num;
352 typedef struct {
353 struct list entry;
354 const WCHAR *font_name;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 LPCWSTR name;
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
383 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
384 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
386 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
387 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
388 'W','i','n','d','o','w','s','\\',
389 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
390 'F','o','n','t','s','\0'};
392 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
393 'W','i','n','d','o','w','s',' ','N','T','\\',
394 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
395 'F','o','n','t','s','\0'};
397 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
398 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
399 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
400 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
402 static const WCHAR * const SystemFontValues[4] = {
403 System_Value,
404 OEMFont_Value,
405 FixedSys_Value,
406 NULL
409 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
410 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
412 /* Interesting and well-known (frequently-assumed!) font names */
413 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
414 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 };
415 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
416 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
417 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
418 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
419 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
420 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
422 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
423 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
424 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
425 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
426 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
427 'E','u','r','o','p','e','a','n','\0'};
428 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
429 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
430 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
431 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
432 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
433 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
434 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
435 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
436 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
437 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
438 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
439 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
441 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
442 WesternW, /*00*/
443 Central_EuropeanW,
444 CyrillicW,
445 GreekW,
446 TurkishW,
447 HebrewW,
448 ArabicW,
449 BalticW,
450 VietnameseW, /*08*/
451 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
452 ThaiW,
453 JapaneseW,
454 CHINESE_GB2312W,
455 HangulW,
456 CHINESE_BIG5W,
457 Hangul_Johab_W,
458 NULL, NULL, /*23*/
459 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
460 SymbolW /*31*/
463 typedef struct {
464 WCHAR *name;
465 INT charset;
466 } NameCs;
468 typedef struct tagFontSubst {
469 struct list entry;
470 NameCs from;
471 NameCs to;
472 } FontSubst;
474 struct font_mapping
476 struct list entry;
477 int refcount;
478 dev_t dev;
479 ino_t ino;
480 void *data;
481 size_t size;
484 static struct list mappings_list = LIST_INIT( mappings_list );
486 static CRITICAL_SECTION freetype_cs;
487 static CRITICAL_SECTION_DEBUG critsect_debug =
489 0, 0, &freetype_cs,
490 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
491 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
493 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
495 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
497 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
498 static BOOL use_default_fallback = FALSE;
500 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
502 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
503 'W','i','n','d','o','w','s',' ','N','T','\\',
504 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
505 'S','y','s','t','e','m','L','i','n','k',0};
507 /****************************************
508 * Notes on .fon files
510 * The fonts System, FixedSys and Terminal are special. There are typically multiple
511 * versions installed for different resolutions and codepages. Windows stores which one to use
512 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
513 * Key Meaning
514 * FIXEDFON.FON FixedSys
515 * FONTS.FON System
516 * OEMFONT.FON Terminal
517 * LogPixels Current dpi set by the display control panel applet
518 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
519 * also has a LogPixels value that appears to mirror this)
521 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
522 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
523 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
524 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
525 * so that makes sense.
527 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
528 * to be mapped into the registry on Windows 2000 at least).
529 * I have
530 * woafont=app850.fon
531 * ega80woa.fon=ega80850.fon
532 * ega40woa.fon=ega40850.fon
533 * cga80woa.fon=cga80850.fon
534 * cga40woa.fon=cga40850.fon
537 /* These are all structures needed for the GSUB table */
539 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
540 #define TATEGAKI_LOWER_BOUND 0x02F1
542 typedef struct {
543 DWORD version;
544 WORD ScriptList;
545 WORD FeatureList;
546 WORD LookupList;
547 } GSUB_Header;
549 typedef struct {
550 CHAR ScriptTag[4];
551 WORD Script;
552 } GSUB_ScriptRecord;
554 typedef struct {
555 WORD ScriptCount;
556 GSUB_ScriptRecord ScriptRecord[1];
557 } GSUB_ScriptList;
559 typedef struct {
560 CHAR LangSysTag[4];
561 WORD LangSys;
562 } GSUB_LangSysRecord;
564 typedef struct {
565 WORD DefaultLangSys;
566 WORD LangSysCount;
567 GSUB_LangSysRecord LangSysRecord[1];
568 } GSUB_Script;
570 typedef struct {
571 WORD LookupOrder; /* Reserved */
572 WORD ReqFeatureIndex;
573 WORD FeatureCount;
574 WORD FeatureIndex[1];
575 } GSUB_LangSys;
577 typedef struct {
578 CHAR FeatureTag[4];
579 WORD Feature;
580 } GSUB_FeatureRecord;
582 typedef struct {
583 WORD FeatureCount;
584 GSUB_FeatureRecord FeatureRecord[1];
585 } GSUB_FeatureList;
587 typedef struct {
588 WORD FeatureParams; /* Reserved */
589 WORD LookupCount;
590 WORD LookupListIndex[1];
591 } GSUB_Feature;
593 typedef struct {
594 WORD LookupCount;
595 WORD Lookup[1];
596 } GSUB_LookupList;
598 typedef struct {
599 WORD LookupType;
600 WORD LookupFlag;
601 WORD SubTableCount;
602 WORD SubTable[1];
603 } GSUB_LookupTable;
605 typedef struct {
606 WORD CoverageFormat;
607 WORD GlyphCount;
608 WORD GlyphArray[1];
609 } GSUB_CoverageFormat1;
611 typedef struct {
612 WORD Start;
613 WORD End;
614 WORD StartCoverageIndex;
615 } GSUB_RangeRecord;
617 typedef struct {
618 WORD CoverageFormat;
619 WORD RangeCount;
620 GSUB_RangeRecord RangeRecord[1];
621 } GSUB_CoverageFormat2;
623 typedef struct {
624 WORD SubstFormat; /* = 1 */
625 WORD Coverage;
626 WORD DeltaGlyphID;
627 } GSUB_SingleSubstFormat1;
629 typedef struct {
630 WORD SubstFormat; /* = 2 */
631 WORD Coverage;
632 WORD GlyphCount;
633 WORD Substitute[1];
634 }GSUB_SingleSubstFormat2;
636 #ifdef HAVE_CARBON_CARBON_H
637 static char *find_cache_dir(void)
639 FSRef ref;
640 OSErr err;
641 static char cached_path[MAX_PATH];
642 static const char *wine = "/Wine", *fonts = "/Fonts";
644 if(*cached_path) return cached_path;
646 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
647 if(err != noErr)
649 WARN("can't create cached data folder\n");
650 return NULL;
652 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
653 if(err != noErr)
655 WARN("can't create cached data path\n");
656 *cached_path = '\0';
657 return NULL;
659 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
661 ERR("Could not create full path\n");
662 *cached_path = '\0';
663 return NULL;
665 strcat(cached_path, wine);
667 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
669 WARN("Couldn't mkdir %s\n", cached_path);
670 *cached_path = '\0';
671 return NULL;
673 strcat(cached_path, fonts);
674 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
676 WARN("Couldn't mkdir %s\n", cached_path);
677 *cached_path = '\0';
678 return NULL;
680 return cached_path;
683 /******************************************************************
684 * expand_mac_font
686 * Extracts individual TrueType font files from a Mac suitcase font
687 * and saves them into the user's caches directory (see
688 * find_cache_dir()).
689 * Returns a NULL terminated array of filenames.
691 * We do this because they are apps that try to read ttf files
692 * themselves and they don't like Mac suitcase files.
694 static char **expand_mac_font(const char *path)
696 FSRef ref;
697 SInt16 res_ref;
698 OSStatus s;
699 unsigned int idx;
700 const char *out_dir;
701 const char *filename;
702 int output_len;
703 struct {
704 char **array;
705 unsigned int size, max_size;
706 } ret;
708 TRACE("path %s\n", path);
710 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
711 if(s != noErr)
713 WARN("failed to get ref\n");
714 return NULL;
717 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
718 if(s != noErr)
720 TRACE("no data fork, so trying resource fork\n");
721 res_ref = FSOpenResFile(&ref, fsRdPerm);
722 if(res_ref == -1)
724 TRACE("unable to open resource fork\n");
725 return NULL;
729 ret.size = 0;
730 ret.max_size = 10;
731 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
732 if(!ret.array)
734 CloseResFile(res_ref);
735 return NULL;
738 out_dir = find_cache_dir();
740 filename = strrchr(path, '/');
741 if(!filename) filename = path;
742 else filename++;
744 /* output filename has the form out_dir/filename_%04x.ttf */
745 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
747 UseResFile(res_ref);
748 idx = 1;
749 while(1)
751 FamRec *fam_rec;
752 unsigned short *num_faces_ptr, num_faces, face;
753 AsscEntry *assoc;
754 Handle fond;
755 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
757 fond = Get1IndResource(fond_res, idx);
758 if(!fond) break;
759 TRACE("got fond resource %d\n", idx);
760 HLock(fond);
762 fam_rec = *(FamRec**)fond;
763 num_faces_ptr = (unsigned short *)(fam_rec + 1);
764 num_faces = GET_BE_WORD(*num_faces_ptr);
765 num_faces++;
766 assoc = (AsscEntry*)(num_faces_ptr + 1);
767 TRACE("num faces %04x\n", num_faces);
768 for(face = 0; face < num_faces; face++, assoc++)
770 Handle sfnt;
771 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
772 unsigned short size, font_id;
773 char *output;
775 size = GET_BE_WORD(assoc->fontSize);
776 font_id = GET_BE_WORD(assoc->fontID);
777 if(size != 0)
779 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
780 continue;
783 TRACE("trying to load sfnt id %04x\n", font_id);
784 sfnt = GetResource(sfnt_res, font_id);
785 if(!sfnt)
787 TRACE("can't get sfnt resource %04x\n", font_id);
788 continue;
791 output = HeapAlloc(GetProcessHeap(), 0, output_len);
792 if(output)
794 int fd;
796 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
798 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
799 if(fd != -1 || errno == EEXIST)
801 if(fd != -1)
803 unsigned char *sfnt_data;
805 HLock(sfnt);
806 sfnt_data = *(unsigned char**)sfnt;
807 write(fd, sfnt_data, GetHandleSize(sfnt));
808 HUnlock(sfnt);
809 close(fd);
811 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
813 ret.max_size *= 2;
814 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
816 ret.array[ret.size++] = output;
818 else
820 WARN("unable to create %s\n", output);
821 HeapFree(GetProcessHeap(), 0, output);
824 ReleaseResource(sfnt);
826 HUnlock(fond);
827 ReleaseResource(fond);
828 idx++;
830 CloseResFile(res_ref);
832 return ret.array;
835 #endif /* HAVE_CARBON_CARBON_H */
837 static inline BOOL is_win9x(void)
839 return GetVersion() & 0x80000000;
842 This function builds an FT_Fixed from a double. It fails if the absolute
843 value of the float number is greater than 32768.
845 static inline FT_Fixed FT_FixedFromFloat(double f)
847 return f * 0x10000;
851 This function builds an FT_Fixed from a FIXED. It simply put f.value
852 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
854 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
856 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
860 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
862 Family *family;
863 Face *face;
864 const char *file;
865 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
866 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
868 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
869 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
871 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
873 if(face_name && strcmpiW(face_name, family->FamilyName))
874 continue;
875 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
877 if (!face->file)
878 continue;
879 file = strrchr(face->file, '/');
880 if(!file)
881 file = face->file;
882 else
883 file++;
884 if(!strcasecmp(file, file_nameA))
886 HeapFree(GetProcessHeap(), 0, file_nameA);
887 return face;
891 HeapFree(GetProcessHeap(), 0, file_nameA);
892 return NULL;
895 static Family *find_family_from_name(const WCHAR *name)
897 Family *family;
899 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
901 if(!strcmpiW(family->FamilyName, name))
902 return family;
905 return NULL;
908 static void DumpSubstList(void)
910 FontSubst *psub;
912 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
914 if(psub->from.charset != -1 || psub->to.charset != -1)
915 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
916 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
917 else
918 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
919 debugstr_w(psub->to.name));
921 return;
924 static LPWSTR strdupW(LPCWSTR p)
926 LPWSTR ret;
927 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
928 ret = HeapAlloc(GetProcessHeap(), 0, len);
929 memcpy(ret, p, len);
930 return ret;
933 static LPSTR strdupA(LPCSTR p)
935 LPSTR ret;
936 DWORD len = (strlen(p) + 1);
937 ret = HeapAlloc(GetProcessHeap(), 0, len);
938 memcpy(ret, p, len);
939 return ret;
942 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
943 INT from_charset)
945 FontSubst *element;
947 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
949 if(!strcmpiW(element->from.name, from_name) &&
950 (element->from.charset == from_charset ||
951 element->from.charset == -1))
952 return element;
955 return NULL;
958 #define ADD_FONT_SUBST_FORCE 1
960 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
962 FontSubst *from_exist, *to_exist;
964 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
966 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
968 list_remove(&from_exist->entry);
969 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
970 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
971 HeapFree(GetProcessHeap(), 0, from_exist);
972 from_exist = NULL;
975 if(!from_exist)
977 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
979 if(to_exist)
981 HeapFree(GetProcessHeap(), 0, subst->to.name);
982 subst->to.name = strdupW(to_exist->to.name);
985 list_add_tail(subst_list, &subst->entry);
987 return TRUE;
990 HeapFree(GetProcessHeap(), 0, subst->from.name);
991 HeapFree(GetProcessHeap(), 0, subst->to.name);
992 HeapFree(GetProcessHeap(), 0, subst);
993 return FALSE;
996 static void split_subst_info(NameCs *nc, LPSTR str)
998 CHAR *p = strrchr(str, ',');
999 DWORD len;
1001 nc->charset = -1;
1002 if(p && *(p+1)) {
1003 nc->charset = strtol(p+1, NULL, 10);
1004 *p = '\0';
1006 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1007 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1008 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1011 static void LoadSubstList(void)
1013 FontSubst *psub;
1014 HKEY hkey;
1015 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1016 LPSTR value;
1017 LPVOID data;
1019 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1020 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1021 &hkey) == ERROR_SUCCESS) {
1023 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1024 &valuelen, &datalen, NULL, NULL);
1026 valuelen++; /* returned value doesn't include room for '\0' */
1027 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1028 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1030 dlen = datalen;
1031 vlen = valuelen;
1032 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1033 &dlen) == ERROR_SUCCESS) {
1034 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1036 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1037 split_subst_info(&psub->from, value);
1038 split_subst_info(&psub->to, data);
1040 /* Win 2000 doesn't allow mapping between different charsets
1041 or mapping of DEFAULT_CHARSET */
1042 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1043 psub->to.charset == DEFAULT_CHARSET) {
1044 HeapFree(GetProcessHeap(), 0, psub->to.name);
1045 HeapFree(GetProcessHeap(), 0, psub->from.name);
1046 HeapFree(GetProcessHeap(), 0, psub);
1047 } else {
1048 add_font_subst(&font_subst_list, psub, 0);
1050 /* reset dlen and vlen */
1051 dlen = datalen;
1052 vlen = valuelen;
1054 HeapFree(GetProcessHeap(), 0, data);
1055 HeapFree(GetProcessHeap(), 0, value);
1056 RegCloseKey(hkey);
1061 /*****************************************************************
1062 * get_name_table_entry
1064 * Supply the platform, encoding, language and name ids in req
1065 * and if the name exists the function will fill in the string
1066 * and string_len members. The string is owned by FreeType so
1067 * don't free it. Returns TRUE if the name is found else FALSE.
1069 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1071 FT_SfntName name;
1072 FT_UInt num_names, name_index;
1074 if(FT_IS_SFNT(ft_face))
1076 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1078 for(name_index = 0; name_index < num_names; name_index++)
1080 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1082 if((name.platform_id == req->platform_id) &&
1083 (name.encoding_id == req->encoding_id) &&
1084 (name.language_id == req->language_id) &&
1085 (name.name_id == req->name_id))
1087 req->string = name.string;
1088 req->string_len = name.string_len;
1089 return TRUE;
1094 req->string = NULL;
1095 req->string_len = 0;
1096 return FALSE;
1099 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1101 WCHAR *ret = NULL;
1102 FT_SfntName name;
1104 name.platform_id = TT_PLATFORM_MICROSOFT;
1105 name.encoding_id = TT_MS_ID_UNICODE_CS;
1106 name.language_id = language_id;
1107 name.name_id = name_id;
1109 if(get_name_table_entry(ft_face, &name))
1111 FT_UInt i;
1113 /* String is not nul terminated and string_len is a byte length. */
1114 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1115 for(i = 0; i < name.string_len / 2; i++)
1117 WORD *tmp = (WORD *)&name.string[i * 2];
1118 ret[i] = GET_BE_WORD(*tmp);
1120 ret[i] = 0;
1121 TRACE("Got localised name %s\n", debugstr_w(ret));
1124 return ret;
1128 /*****************************************************************
1129 * load_sfnt_table
1131 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1132 * of FreeType that don't export this function.
1135 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1138 FT_Error err;
1140 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1141 if(pFT_Load_Sfnt_Table)
1143 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1145 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1146 else /* Do it the hard way */
1148 TT_Face tt_face = (TT_Face) ft_face;
1149 SFNT_Interface *sfnt;
1150 if (FT_Version.major==2 && FT_Version.minor==0)
1152 /* 2.0.x */
1153 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1155 else
1157 /* A field was added in the middle of the structure in 2.1.x */
1158 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1160 err = sfnt->load_any(tt_face, table, offset, buf, len);
1162 #else
1163 else
1165 static int msg;
1166 if(!msg)
1168 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1169 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1170 "Please upgrade your freetype library.\n");
1171 msg++;
1173 err = FT_Err_Unimplemented_Feature;
1175 #endif
1176 return err;
1179 static inline int TestStyles(DWORD flags, DWORD styles)
1181 return (flags & styles) == styles;
1184 static int StyleOrdering(Face *face)
1186 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1187 return 3;
1188 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1189 return 2;
1190 if (TestStyles(face->ntmFlags, NTM_BOLD))
1191 return 1;
1192 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1193 return 0;
1195 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1196 debugstr_w(face->family->FamilyName),
1197 debugstr_w(face->StyleName),
1198 face->ntmFlags);
1200 return 9999;
1203 /* Add a style of face to a font family using an ordering of the list such
1204 that regular fonts come before bold and italic, and single styles come
1205 before compound styles. */
1206 static void AddFaceToFamily(Face *face, Family *family)
1208 struct list *entry;
1210 LIST_FOR_EACH( entry, &family->faces )
1212 Face *ent = LIST_ENTRY(entry, Face, entry);
1213 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1215 list_add_before( entry, &face->entry );
1218 #define ADDFONT_EXTERNAL_FONT 0x01
1219 #define ADDFONT_FORCE_BITMAP 0x02
1220 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1222 FT_Face ft_face;
1223 TT_OS2 *pOS2;
1224 TT_Header *pHeader = NULL;
1225 WCHAR *english_family, *localised_family, *StyleW;
1226 DWORD len;
1227 Family *family;
1228 Face *face;
1229 struct list *family_elem_ptr, *face_elem_ptr;
1230 FT_Error err;
1231 FT_Long face_index = 0, num_faces;
1232 #ifdef HAVE_FREETYPE_FTWINFNT_H
1233 FT_WinFNT_HeaderRec winfnt_header;
1234 #endif
1235 int i, bitmap_num, internal_leading;
1236 FONTSIGNATURE fs;
1238 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1239 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1241 #ifdef HAVE_CARBON_CARBON_H
1242 if(file && !fake_family)
1244 char **mac_list = expand_mac_font(file);
1245 if(mac_list)
1247 BOOL had_one = FALSE;
1248 char **cursor;
1249 for(cursor = mac_list; *cursor; cursor++)
1251 had_one = TRUE;
1252 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1253 HeapFree(GetProcessHeap(), 0, *cursor);
1255 HeapFree(GetProcessHeap(), 0, mac_list);
1256 if(had_one)
1257 return 1;
1260 #endif /* HAVE_CARBON_CARBON_H */
1262 do {
1263 char *family_name = fake_family;
1265 if (file)
1267 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1268 err = pFT_New_Face(library, file, face_index, &ft_face);
1269 } else
1271 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1272 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1275 if(err != 0) {
1276 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1277 return 0;
1280 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*/
1281 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1282 pFT_Done_Face(ft_face);
1283 return 0;
1286 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1287 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1288 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1289 pFT_Done_Face(ft_face);
1290 return 0;
1293 if(FT_IS_SFNT(ft_face))
1295 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1296 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1297 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1299 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1300 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1301 pFT_Done_Face(ft_face);
1302 return 0;
1305 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1306 we don't want to load these. */
1307 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1309 FT_ULong len = 0;
1311 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1313 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1314 pFT_Done_Face(ft_face);
1315 return 0;
1320 if(!ft_face->family_name || !ft_face->style_name) {
1321 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1322 pFT_Done_Face(ft_face);
1323 return 0;
1326 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1328 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1329 pFT_Done_Face(ft_face);
1330 return 0;
1333 if (target_family)
1335 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1336 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1338 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1339 HeapFree(GetProcessHeap(), 0, localised_family);
1340 num_faces = ft_face->num_faces;
1341 pFT_Done_Face(ft_face);
1342 continue;
1344 HeapFree(GetProcessHeap(), 0, localised_family);
1347 if(!family_name)
1348 family_name = ft_face->family_name;
1350 bitmap_num = 0;
1351 do {
1352 My_FT_Bitmap_Size *size = NULL;
1353 FT_ULong tmp_size;
1355 if(!FT_IS_SCALABLE(ft_face))
1356 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1358 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1359 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1360 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1362 localised_family = NULL;
1363 if(!fake_family) {
1364 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1365 if(localised_family && !strcmpiW(localised_family, english_family)) {
1366 HeapFree(GetProcessHeap(), 0, localised_family);
1367 localised_family = NULL;
1371 family = NULL;
1372 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1373 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1374 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1375 break;
1376 family = NULL;
1378 if(!family) {
1379 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1380 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1381 list_init(&family->faces);
1382 list_add_tail(&font_list, &family->entry);
1384 if(localised_family) {
1385 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1386 subst->from.name = strdupW(english_family);
1387 subst->from.charset = -1;
1388 subst->to.name = strdupW(localised_family);
1389 subst->to.charset = -1;
1390 add_font_subst(&font_subst_list, subst, 0);
1393 HeapFree(GetProcessHeap(), 0, localised_family);
1394 HeapFree(GetProcessHeap(), 0, english_family);
1396 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1397 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1398 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1400 internal_leading = 0;
1401 memset(&fs, 0, sizeof(fs));
1403 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1404 if(pOS2) {
1405 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1406 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1407 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1408 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1409 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1410 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1411 if(pOS2->version == 0) {
1412 FT_UInt dummy;
1414 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1415 fs.fsCsb[0] |= FS_LATIN1;
1416 else
1417 fs.fsCsb[0] |= FS_SYMBOL;
1420 #ifdef HAVE_FREETYPE_FTWINFNT_H
1421 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1422 CHARSETINFO csi;
1423 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1424 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1425 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1426 fs = csi.fs;
1427 internal_leading = winfnt_header.internal_leading;
1429 #endif
1431 face_elem_ptr = list_head(&family->faces);
1432 while(face_elem_ptr) {
1433 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1434 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1435 if(!strcmpiW(face->StyleName, StyleW) &&
1436 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1437 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1438 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1439 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1441 if(fake_family) {
1442 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1443 HeapFree(GetProcessHeap(), 0, StyleW);
1444 pFT_Done_Face(ft_face);
1445 return 1;
1447 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1448 TRACE("Original font is newer so skipping this one\n");
1449 HeapFree(GetProcessHeap(), 0, StyleW);
1450 pFT_Done_Face(ft_face);
1451 return 1;
1452 } else {
1453 TRACE("Replacing original with this one\n");
1454 list_remove(&face->entry);
1455 HeapFree(GetProcessHeap(), 0, face->file);
1456 HeapFree(GetProcessHeap(), 0, face->StyleName);
1457 HeapFree(GetProcessHeap(), 0, face->FullName);
1458 HeapFree(GetProcessHeap(), 0, face);
1459 break;
1463 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1464 face->cached_enum_data = NULL;
1465 face->StyleName = StyleW;
1466 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1467 if (file)
1469 face->file = strdupA(file);
1470 face->font_data_ptr = NULL;
1471 face->font_data_size = 0;
1473 else
1475 face->file = NULL;
1476 face->font_data_ptr = font_data_ptr;
1477 face->font_data_size = font_data_size;
1479 face->face_index = face_index;
1480 face->ntmFlags = 0;
1481 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1482 face->ntmFlags |= NTM_ITALIC;
1483 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1484 face->ntmFlags |= NTM_BOLD;
1485 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1486 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1487 face->family = family;
1488 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1489 face->fs = fs;
1490 memset(&face->fs_links, 0, sizeof(face->fs_links));
1492 if(FT_IS_SCALABLE(ft_face)) {
1493 memset(&face->size, 0, sizeof(face->size));
1494 face->scalable = TRUE;
1495 } else {
1496 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1497 size->height, size->width, size->size >> 6,
1498 size->x_ppem >> 6, size->y_ppem >> 6);
1499 face->size.height = size->height;
1500 face->size.width = size->width;
1501 face->size.size = size->size;
1502 face->size.x_ppem = size->x_ppem;
1503 face->size.y_ppem = size->y_ppem;
1504 face->size.internal_leading = internal_leading;
1505 face->scalable = FALSE;
1508 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1509 tmp_size = 0;
1510 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1512 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1513 face->ntmFlags |= NTM_PS_OPENTYPE;
1516 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1517 face->fs.fsCsb[0], face->fs.fsCsb[1],
1518 face->fs.fsUsb[0], face->fs.fsUsb[1],
1519 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1522 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1523 for(i = 0; i < ft_face->num_charmaps; i++) {
1524 switch(ft_face->charmaps[i]->encoding) {
1525 case FT_ENCODING_UNICODE:
1526 case FT_ENCODING_APPLE_ROMAN:
1527 face->fs.fsCsb[0] |= FS_LATIN1;
1528 break;
1529 case FT_ENCODING_MS_SYMBOL:
1530 face->fs.fsCsb[0] |= FS_SYMBOL;
1531 break;
1532 default:
1533 break;
1538 AddFaceToFamily(face, family);
1540 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1542 num_faces = ft_face->num_faces;
1543 pFT_Done_Face(ft_face);
1544 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1545 debugstr_w(StyleW));
1546 } while(num_faces > ++face_index);
1547 return num_faces;
1550 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1552 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1555 static void DumpFontList(void)
1557 Family *family;
1558 Face *face;
1559 struct list *family_elem_ptr, *face_elem_ptr;
1561 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1562 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1563 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1564 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1565 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1566 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1567 if(!face->scalable)
1568 TRACE(" %d", face->size.height);
1569 TRACE("\n");
1572 return;
1575 /***********************************************************
1576 * The replacement list is a way to map an entire font
1577 * family onto another family. For example adding
1579 * [HKCU\Software\Wine\Fonts\Replacements]
1580 * "Wingdings"="Winedings"
1582 * would enumerate the Winedings font both as Winedings and
1583 * Wingdings. However if a real Wingdings font is present the
1584 * replacement does not take place.
1587 static void LoadReplaceList(void)
1589 HKEY hkey;
1590 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1591 LPWSTR value;
1592 LPVOID data;
1593 Family *family;
1594 Face *face;
1595 struct list *family_elem_ptr, *face_elem_ptr;
1596 CHAR familyA[400];
1598 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1599 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1601 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1602 &valuelen, &datalen, NULL, NULL);
1604 valuelen++; /* returned value doesn't include room for '\0' */
1605 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1606 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1608 dlen = datalen;
1609 vlen = valuelen;
1610 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1611 &dlen) == ERROR_SUCCESS) {
1612 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1613 /* "NewName"="Oldname" */
1614 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1616 /* Find the old family and hence all of the font files
1617 in that family */
1618 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1619 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1620 if(!strcmpiW(family->FamilyName, data)) {
1621 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1622 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1623 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1624 debugstr_w(face->StyleName), familyA);
1625 /* Now add a new entry with the new family name */
1626 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1628 break;
1631 /* reset dlen and vlen */
1632 dlen = datalen;
1633 vlen = valuelen;
1635 HeapFree(GetProcessHeap(), 0, data);
1636 HeapFree(GetProcessHeap(), 0, value);
1637 RegCloseKey(hkey);
1641 /*************************************************************
1642 * init_system_links
1644 static BOOL init_system_links(void)
1646 HKEY hkey;
1647 BOOL ret = FALSE;
1648 DWORD type, max_val, max_data, val_len, data_len, index;
1649 WCHAR *value, *data;
1650 WCHAR *entry, *next;
1651 SYSTEM_LINKS *font_link, *system_font_link;
1652 CHILD_FONT *child_font;
1653 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1654 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1655 FONTSIGNATURE fs;
1656 Family *family;
1657 Face *face;
1658 FontSubst *psub;
1660 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1662 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1663 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1664 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1665 val_len = max_val + 1;
1666 data_len = max_data;
1667 index = 0;
1668 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1670 memset(&fs, 0, sizeof(fs));
1671 psub = get_font_subst(&font_subst_list, value, -1);
1672 /* Don't store fonts that are only substitutes for other fonts */
1673 if(psub)
1675 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1676 goto next;
1678 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1679 font_link->font_name = strdupW(value);
1680 list_init(&font_link->links);
1681 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1683 WCHAR *face_name;
1684 CHILD_FONT *child_font;
1686 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1688 next = entry + strlenW(entry) + 1;
1690 face_name = strchrW(entry, ',');
1691 if(face_name)
1693 *face_name++ = 0;
1694 while(isspaceW(*face_name))
1695 face_name++;
1697 psub = get_font_subst(&font_subst_list, face_name, -1);
1698 if(psub)
1699 face_name = psub->to.name;
1701 face = find_face_from_filename(entry, face_name);
1702 if(!face)
1704 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1705 continue;
1708 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1709 child_font->face = face;
1710 child_font->font = NULL;
1711 fs.fsCsb[0] |= face->fs.fsCsb[0];
1712 fs.fsCsb[1] |= face->fs.fsCsb[1];
1713 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1714 list_add_tail(&font_link->links, &child_font->entry);
1716 family = find_family_from_name(font_link->font_name);
1717 if(family)
1719 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1721 face->fs_links = fs;
1724 list_add_tail(&system_links, &font_link->entry);
1725 next:
1726 val_len = max_val + 1;
1727 data_len = max_data;
1730 HeapFree(GetProcessHeap(), 0, value);
1731 HeapFree(GetProcessHeap(), 0, data);
1732 RegCloseKey(hkey);
1735 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1736 that Tahoma has */
1738 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1739 system_font_link->font_name = strdupW(System);
1740 list_init(&system_font_link->links);
1742 face = find_face_from_filename(tahoma_ttf, Tahoma);
1743 if(face)
1745 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1746 child_font->face = face;
1747 child_font->font = NULL;
1748 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1749 list_add_tail(&system_font_link->links, &child_font->entry);
1751 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1753 if(!strcmpiW(font_link->font_name, Tahoma))
1755 CHILD_FONT *font_link_entry;
1756 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1758 CHILD_FONT *new_child;
1759 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1760 new_child->face = font_link_entry->face;
1761 new_child->font = NULL;
1762 list_add_tail(&system_font_link->links, &new_child->entry);
1764 break;
1767 list_add_tail(&system_links, &system_font_link->entry);
1768 return ret;
1771 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1773 DIR *dir;
1774 struct dirent *dent;
1775 char path[MAX_PATH];
1777 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1779 dir = opendir(dirname);
1780 if(!dir) {
1781 WARN("Can't open directory %s\n", debugstr_a(dirname));
1782 return FALSE;
1784 while((dent = readdir(dir)) != NULL) {
1785 struct stat statbuf;
1787 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1788 continue;
1790 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1792 sprintf(path, "%s/%s", dirname, dent->d_name);
1794 if(stat(path, &statbuf) == -1)
1796 WARN("Can't stat %s\n", debugstr_a(path));
1797 continue;
1799 if(S_ISDIR(statbuf.st_mode))
1800 ReadFontDir(path, external_fonts);
1801 else
1802 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1804 closedir(dir);
1805 return TRUE;
1808 static void load_fontconfig_fonts(void)
1810 #ifdef SONAME_LIBFONTCONFIG
1811 void *fc_handle = NULL;
1812 FcConfig *config;
1813 FcPattern *pat;
1814 FcObjectSet *os;
1815 FcFontSet *fontset;
1816 int i, len;
1817 char *file;
1818 const char *ext;
1820 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1821 if(!fc_handle) {
1822 TRACE("Wine cannot find the fontconfig library (%s).\n",
1823 SONAME_LIBFONTCONFIG);
1824 return;
1826 #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;}
1827 LOAD_FUNCPTR(FcConfigGetCurrent);
1828 LOAD_FUNCPTR(FcFontList);
1829 LOAD_FUNCPTR(FcFontSetDestroy);
1830 LOAD_FUNCPTR(FcInit);
1831 LOAD_FUNCPTR(FcObjectSetAdd);
1832 LOAD_FUNCPTR(FcObjectSetCreate);
1833 LOAD_FUNCPTR(FcObjectSetDestroy);
1834 LOAD_FUNCPTR(FcPatternCreate);
1835 LOAD_FUNCPTR(FcPatternDestroy);
1836 LOAD_FUNCPTR(FcPatternGetBool);
1837 LOAD_FUNCPTR(FcPatternGetString);
1838 #undef LOAD_FUNCPTR
1840 if(!pFcInit()) return;
1842 config = pFcConfigGetCurrent();
1843 pat = pFcPatternCreate();
1844 os = pFcObjectSetCreate();
1845 pFcObjectSetAdd(os, FC_FILE);
1846 pFcObjectSetAdd(os, FC_SCALABLE);
1847 fontset = pFcFontList(config, pat, os);
1848 if(!fontset) return;
1849 for(i = 0; i < fontset->nfont; i++) {
1850 FcBool scalable;
1852 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1853 continue;
1854 TRACE("fontconfig: %s\n", file);
1856 /* We're just interested in OT/TT fonts for now, so this hack just
1857 picks up the scalable fonts without extensions .pf[ab] to save time
1858 loading every other font */
1860 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1862 TRACE("not scalable\n");
1863 continue;
1866 len = strlen( file );
1867 if(len < 4) continue;
1868 ext = &file[ len - 3 ];
1869 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1870 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1872 pFcFontSetDestroy(fontset);
1873 pFcObjectSetDestroy(os);
1874 pFcPatternDestroy(pat);
1875 sym_not_found:
1876 #endif
1877 return;
1880 static BOOL load_font_from_data_dir(LPCWSTR file)
1882 BOOL ret = FALSE;
1883 const char *data_dir = wine_get_data_dir();
1885 if (!data_dir) data_dir = wine_get_build_dir();
1887 if (data_dir)
1889 INT len;
1890 char *unix_name;
1892 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1894 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1896 strcpy(unix_name, data_dir);
1897 strcat(unix_name, "/fonts/");
1899 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1901 EnterCriticalSection( &freetype_cs );
1902 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1903 LeaveCriticalSection( &freetype_cs );
1904 HeapFree(GetProcessHeap(), 0, unix_name);
1906 return ret;
1909 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1911 static const WCHAR slashW[] = {'\\','\0'};
1912 BOOL ret = FALSE;
1913 WCHAR windowsdir[MAX_PATH];
1914 char *unixname;
1916 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1917 strcatW(windowsdir, fontsW);
1918 strcatW(windowsdir, slashW);
1919 strcatW(windowsdir, file);
1920 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1921 EnterCriticalSection( &freetype_cs );
1922 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1923 LeaveCriticalSection( &freetype_cs );
1924 HeapFree(GetProcessHeap(), 0, unixname);
1926 return ret;
1929 static void load_system_fonts(void)
1931 HKEY hkey;
1932 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1933 const WCHAR * const *value;
1934 DWORD dlen, type;
1935 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1936 char *unixname;
1938 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1939 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1940 strcatW(windowsdir, fontsW);
1941 for(value = SystemFontValues; *value; value++) {
1942 dlen = sizeof(data);
1943 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1944 type == REG_SZ) {
1945 BOOL added = FALSE;
1947 sprintfW(pathW, fmtW, windowsdir, data);
1948 if((unixname = wine_get_unix_file_name(pathW))) {
1949 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1950 HeapFree(GetProcessHeap(), 0, unixname);
1952 if (!added)
1953 load_font_from_data_dir(data);
1956 RegCloseKey(hkey);
1960 /*************************************************************
1962 * This adds registry entries for any externally loaded fonts
1963 * (fonts from fontconfig or FontDirs). It also deletes entries
1964 * of no longer existing fonts.
1967 static void update_reg_entries(void)
1969 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1970 LPWSTR valueW;
1971 DWORD len, len_fam;
1972 Family *family;
1973 Face *face;
1974 struct list *family_elem_ptr, *face_elem_ptr;
1975 WCHAR *file;
1976 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1977 static const WCHAR spaceW[] = {' ', '\0'};
1978 char *path;
1980 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1981 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1982 ERR("Can't create Windows font reg key\n");
1983 goto end;
1986 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1987 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1988 ERR("Can't create Windows font reg key\n");
1989 goto end;
1992 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1993 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1994 ERR("Can't create external font reg key\n");
1995 goto end;
1998 /* enumerate the fonts and add external ones to the two keys */
2000 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2001 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2002 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2003 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2004 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2005 if(!face->external) continue;
2006 len = len_fam;
2007 if (!(face->ntmFlags & NTM_REGULAR))
2008 len = len_fam + strlenW(face->StyleName) + 1;
2009 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2010 strcpyW(valueW, family->FamilyName);
2011 if(len != len_fam) {
2012 strcatW(valueW, spaceW);
2013 strcatW(valueW, face->StyleName);
2015 strcatW(valueW, TrueType);
2017 file = wine_get_dos_file_name(face->file);
2018 if(file)
2019 len = strlenW(file) + 1;
2020 else
2022 if((path = strrchr(face->file, '/')) == NULL)
2023 path = face->file;
2024 else
2025 path++;
2026 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2028 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2029 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2031 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2032 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2033 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2035 HeapFree(GetProcessHeap(), 0, file);
2036 HeapFree(GetProcessHeap(), 0, valueW);
2039 end:
2040 if(external_key) RegCloseKey(external_key);
2041 if(win9x_key) RegCloseKey(win9x_key);
2042 if(winnt_key) RegCloseKey(winnt_key);
2043 return;
2046 static void delete_external_font_keys(void)
2048 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2049 DWORD dlen, vlen, datalen, valuelen, i, type;
2050 LPWSTR valueW;
2051 LPVOID data;
2053 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2054 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2055 ERR("Can't create Windows font reg key\n");
2056 goto end;
2059 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2060 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2061 ERR("Can't create Windows font reg key\n");
2062 goto end;
2065 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2066 ERR("Can't create external font reg key\n");
2067 goto end;
2070 /* Delete all external fonts added last time */
2072 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2073 &valuelen, &datalen, NULL, NULL);
2074 valuelen++; /* returned value doesn't include room for '\0' */
2075 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2076 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2078 dlen = datalen * sizeof(WCHAR);
2079 vlen = valuelen;
2080 i = 0;
2081 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2082 &dlen) == ERROR_SUCCESS) {
2084 RegDeleteValueW(winnt_key, valueW);
2085 RegDeleteValueW(win9x_key, valueW);
2086 /* reset dlen and vlen */
2087 dlen = datalen;
2088 vlen = valuelen;
2090 HeapFree(GetProcessHeap(), 0, data);
2091 HeapFree(GetProcessHeap(), 0, valueW);
2093 /* Delete the old external fonts key */
2094 RegCloseKey(external_key);
2095 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2097 end:
2098 if(win9x_key) RegCloseKey(win9x_key);
2099 if(winnt_key) RegCloseKey(winnt_key);
2102 /*************************************************************
2103 * WineEngAddFontResourceEx
2106 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2108 INT ret = 0;
2110 GDI_CheckNotLock();
2112 if (ft_handle) /* do it only if we have freetype up and running */
2114 char *unixname;
2116 if(flags)
2117 FIXME("Ignoring flags %x\n", flags);
2119 if((unixname = wine_get_unix_file_name(file)))
2121 EnterCriticalSection( &freetype_cs );
2122 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2123 LeaveCriticalSection( &freetype_cs );
2124 HeapFree(GetProcessHeap(), 0, unixname);
2126 if (!ret && !strchrW(file, '\\')) {
2127 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2128 ret = load_font_from_winfonts_dir(file);
2129 if (!ret) {
2130 /* Try in datadir/fonts (or builddir/fonts),
2131 * needed for Magic the Gathering Online
2133 ret = load_font_from_data_dir(file);
2137 return ret;
2140 /*************************************************************
2141 * WineEngAddFontMemResourceEx
2144 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2146 GDI_CheckNotLock();
2148 if (ft_handle) /* do it only if we have freetype up and running */
2150 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2152 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2153 memcpy(pFontCopy, pbFont, cbFont);
2155 EnterCriticalSection( &freetype_cs );
2156 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2157 LeaveCriticalSection( &freetype_cs );
2159 if (*pcFonts == 0)
2161 TRACE("AddFontToList failed\n");
2162 HeapFree(GetProcessHeap(), 0, pFontCopy);
2163 return 0;
2165 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2166 * For now return something unique but quite random
2168 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2169 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2172 *pcFonts = 0;
2173 return 0;
2176 /*************************************************************
2177 * WineEngRemoveFontResourceEx
2180 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2182 GDI_CheckNotLock();
2183 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2184 return TRUE;
2187 static const struct nls_update_font_list
2189 UINT ansi_cp, oem_cp;
2190 const char *oem, *fixed, *system;
2191 const char *courier, *serif, *small, *sserif;
2192 /* these are for font substitutes */
2193 const char *shelldlg, *tmsrmn;
2194 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2195 *helv_0, *tmsrmn_0;
2196 const struct subst
2198 const char *from, *to;
2199 } arial_0, courier_new_0, times_new_roman_0;
2200 } nls_update_font_list[] =
2202 /* Latin 1 (United States) */
2203 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2204 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2205 "Tahoma","Times New Roman",
2206 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2207 { 0 }, { 0 }, { 0 }
2209 /* Latin 1 (Multilingual) */
2210 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2211 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2212 "Tahoma","Times New Roman", /* FIXME unverified */
2213 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2214 { 0 }, { 0 }, { 0 }
2216 /* Eastern Europe */
2217 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2218 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2219 "Tahoma","Times New Roman", /* FIXME unverified */
2220 "Fixedsys,238", "System,238",
2221 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2222 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2223 { "Arial CE,0", "Arial,238" },
2224 { "Courier New CE,0", "Courier New,238" },
2225 { "Times New Roman CE,0", "Times New Roman,238" }
2227 /* Cyrillic */
2228 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2229 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2230 "Tahoma","Times New Roman", /* FIXME unverified */
2231 "Fixedsys,204", "System,204",
2232 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2233 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2234 { "Arial Cyr,0", "Arial,204" },
2235 { "Courier New Cyr,0", "Courier New,204" },
2236 { "Times New Roman Cyr,0", "Times New Roman,204" }
2238 /* Greek */
2239 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2240 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2241 "Tahoma","Times New Roman", /* FIXME unverified */
2242 "Fixedsys,161", "System,161",
2243 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2244 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2245 { "Arial Greek,0", "Arial,161" },
2246 { "Courier New Greek,0", "Courier New,161" },
2247 { "Times New Roman Greek,0", "Times New Roman,161" }
2249 /* Turkish */
2250 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2251 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2252 "Tahoma","Times New Roman", /* FIXME unverified */
2253 "Fixedsys,162", "System,162",
2254 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2255 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2256 { "Arial Tur,0", "Arial,162" },
2257 { "Courier New Tur,0", "Courier New,162" },
2258 { "Times New Roman Tur,0", "Times New Roman,162" }
2260 /* Hebrew */
2261 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2262 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 "Fixedsys,177", "System,177",
2265 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2266 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2267 { 0 }, { 0 }, { 0 }
2269 /* Arabic */
2270 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2271 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2272 "Tahoma","Times New Roman", /* FIXME unverified */
2273 "Fixedsys,178", "System,178",
2274 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2275 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2276 { 0 }, { 0 }, { 0 }
2278 /* Baltic */
2279 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2280 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2281 "Tahoma","Times New Roman", /* FIXME unverified */
2282 "Fixedsys,186", "System,186",
2283 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2284 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2285 { "Arial Baltic,0", "Arial,186" },
2286 { "Courier New Baltic,0", "Courier New,186" },
2287 { "Times New Roman Baltic,0", "Times New Roman,186" }
2289 /* Vietnamese */
2290 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2291 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2292 "Tahoma","Times New Roman", /* FIXME unverified */
2293 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2294 { 0 }, { 0 }, { 0 }
2296 /* Thai */
2297 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2299 "Tahoma","Times New Roman", /* FIXME unverified */
2300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2301 { 0 }, { 0 }, { 0 }
2303 /* Japanese */
2304 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2305 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2306 "MS UI Gothic","MS Serif",
2307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2308 { 0 }, { 0 }, { 0 }
2310 /* Chinese Simplified */
2311 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2312 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2313 "SimSun", "NSimSun",
2314 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2315 { 0 }, { 0 }, { 0 }
2317 /* Korean */
2318 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2319 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2320 "Gulim", "Batang",
2321 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2322 { 0 }, { 0 }, { 0 }
2324 /* Chinese Traditional */
2325 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2327 "PMingLiU", "MingLiU",
2328 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2329 { 0 }, { 0 }, { 0 }
2333 static const WCHAR *font_links_list[] =
2335 Lucida_Sans_Unicode,
2336 Microsoft_Sans_Serif,
2337 Tahoma
2340 static const struct font_links_defaults_list
2342 /* Keyed off substitution for "MS Shell Dlg" */
2343 const WCHAR *shelldlg;
2344 /* Maximum of four substitutes, plus terminating NULL pointer */
2345 const WCHAR *substitutes[5];
2346 } font_links_defaults_list[] =
2348 /* Non East-Asian */
2349 { Tahoma, /* FIXME unverified ordering */
2350 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2352 /* Below lists are courtesy of
2353 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2355 /* Japanese */
2356 { MS_UI_Gothic,
2357 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2359 /* Chinese Simplified */
2360 { SimSun,
2361 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2363 /* Korean */
2364 { Gulim,
2365 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2367 /* Chinese Traditional */
2368 { PMingLiU,
2369 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2373 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2375 return ( ansi_cp == 932 /* CP932 for Japanese */
2376 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2377 || ansi_cp == 949 /* CP949 for Korean */
2378 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2381 static inline HKEY create_fonts_NT_registry_key(void)
2383 HKEY hkey = 0;
2385 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2386 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2387 return hkey;
2390 static inline HKEY create_fonts_9x_registry_key(void)
2392 HKEY hkey = 0;
2394 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2395 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2396 return hkey;
2399 static inline HKEY create_config_fonts_registry_key(void)
2401 HKEY hkey = 0;
2403 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2404 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2405 return hkey;
2408 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2410 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2411 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2412 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2413 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2416 static void set_value_key(HKEY hkey, const char *name, const char *value)
2418 if (value)
2419 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2420 else if (name)
2421 RegDeleteValueA(hkey, name);
2424 static void update_font_info(void)
2426 char buf[40], cpbuf[40];
2427 DWORD len, type;
2428 HKEY hkey = 0;
2429 UINT i, ansi_cp = 0, oem_cp = 0;
2430 BOOL done = FALSE;
2432 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2433 return;
2435 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2436 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2437 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2438 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2439 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2441 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2442 if (is_dbcs_ansi_cp(ansi_cp))
2443 use_default_fallback = TRUE;
2445 len = sizeof(buf);
2446 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2448 if (!strcmp( buf, cpbuf )) /* already set correctly */
2450 RegCloseKey(hkey);
2451 return;
2453 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2455 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2457 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2458 RegCloseKey(hkey);
2460 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2462 HKEY hkey;
2464 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2465 nls_update_font_list[i].oem_cp == oem_cp)
2467 hkey = create_config_fonts_registry_key();
2468 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2469 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2470 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2471 RegCloseKey(hkey);
2473 hkey = create_fonts_NT_registry_key();
2474 add_font_list(hkey, &nls_update_font_list[i]);
2475 RegCloseKey(hkey);
2477 hkey = create_fonts_9x_registry_key();
2478 add_font_list(hkey, &nls_update_font_list[i]);
2479 RegCloseKey(hkey);
2481 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2483 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2484 strlen(nls_update_font_list[i].shelldlg)+1);
2485 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2486 strlen(nls_update_font_list[i].tmsrmn)+1);
2488 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2489 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2490 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2491 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2492 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2493 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2494 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2495 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2497 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2498 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2499 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2501 RegCloseKey(hkey);
2503 done = TRUE;
2505 else
2507 /* Delete the FontSubstitutes from other locales */
2508 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2510 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2511 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2512 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2513 RegCloseKey(hkey);
2517 if (!done)
2518 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2520 /* Clear out system links */
2521 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2524 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2526 const WCHAR *value;
2527 int i;
2528 FontSubst *psub;
2529 Family *family;
2530 Face *face;
2531 const char *file;
2532 WCHAR *fileW;
2533 int fileLen;
2534 WCHAR buff[MAX_PATH];
2535 WCHAR *data;
2536 int entryLen;
2538 static const WCHAR comma[] = {',',0};
2540 RegDeleteValueW(hkey, name);
2541 if (values)
2543 data = buff;
2544 data[0] = '\0';
2545 for (i = 0; values[i] != NULL; i++)
2547 value = values[i];
2548 if (!strcmpiW(name,value))
2549 continue;
2550 psub = get_font_subst(&font_subst_list, value, -1);
2551 if(psub)
2552 value = psub->to.name;
2553 family = find_family_from_name(value);
2554 if (!family)
2555 continue;
2556 file = NULL;
2557 /* Use first extant filename for this Family */
2558 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2560 if (!face->file)
2561 continue;
2562 file = strrchr(face->file, '/');
2563 if (!file)
2564 file = face->file;
2565 else
2566 file++;
2567 break;
2569 if (!file)
2570 continue;
2571 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2572 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2573 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2574 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2575 if (sizeof(buff)-(data-buff) < entryLen + 1)
2577 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2578 HeapFree(GetProcessHeap(), 0, fileW);
2579 break;
2581 strcpyW(data, fileW);
2582 strcatW(data, comma);
2583 strcatW(data, value);
2584 data += entryLen;
2585 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2586 HeapFree(GetProcessHeap(), 0, fileW);
2588 if (data != buff)
2590 *data='\0';
2591 data++;
2592 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2593 } else
2594 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2595 } else
2596 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2599 static void update_system_links(void)
2601 HKEY hkey = 0;
2602 UINT i, j;
2603 BOOL done = FALSE;
2604 DWORD disposition;
2605 FontSubst *psub;
2607 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2609 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2611 if (disposition == REG_OPENED_EXISTING_KEY)
2613 TRACE("SystemLink key already exists, doing nothing\n");
2614 RegCloseKey(hkey);
2615 return;
2618 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2619 if (!psub) {
2620 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2621 RegCloseKey(hkey);
2622 return;
2625 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2627 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2629 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2630 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2632 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2633 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2634 done = TRUE;
2636 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2638 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2641 RegCloseKey(hkey);
2642 if (!done)
2643 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2644 } else
2645 WARN("failed to create SystemLink key\n");
2649 static BOOL init_freetype(void)
2651 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2652 if(!ft_handle) {
2653 WINE_MESSAGE(
2654 "Wine cannot find the FreeType font library. To enable Wine to\n"
2655 "use TrueType fonts please install a version of FreeType greater than\n"
2656 "or equal to 2.0.5.\n"
2657 "http://www.freetype.org\n");
2658 return FALSE;
2661 #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;}
2663 LOAD_FUNCPTR(FT_Vector_Unit)
2664 LOAD_FUNCPTR(FT_Done_Face)
2665 LOAD_FUNCPTR(FT_Get_Char_Index)
2666 LOAD_FUNCPTR(FT_Get_Module)
2667 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2668 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2669 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2670 LOAD_FUNCPTR(FT_Init_FreeType)
2671 LOAD_FUNCPTR(FT_Load_Glyph)
2672 LOAD_FUNCPTR(FT_Matrix_Multiply)
2673 #ifndef FT_MULFIX_INLINED
2674 LOAD_FUNCPTR(FT_MulFix)
2675 #endif
2676 LOAD_FUNCPTR(FT_New_Face)
2677 LOAD_FUNCPTR(FT_New_Memory_Face)
2678 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2679 LOAD_FUNCPTR(FT_Outline_Transform)
2680 LOAD_FUNCPTR(FT_Outline_Translate)
2681 LOAD_FUNCPTR(FT_Select_Charmap)
2682 LOAD_FUNCPTR(FT_Set_Charmap)
2683 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2684 LOAD_FUNCPTR(FT_Vector_Transform)
2685 LOAD_FUNCPTR(FT_Render_Glyph)
2687 #undef LOAD_FUNCPTR
2688 /* Don't warn if these ones are missing */
2689 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2690 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2691 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2692 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2693 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2694 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2695 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2696 #endif
2697 #ifdef HAVE_FREETYPE_FTWINFNT_H
2698 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2699 #endif
2700 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2701 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2702 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2703 <= 2.0.3 has FT_Sqrt64 */
2704 goto sym_not_found;
2707 if(pFT_Init_FreeType(&library) != 0) {
2708 ERR("Can't init FreeType library\n");
2709 wine_dlclose(ft_handle, NULL, 0);
2710 ft_handle = NULL;
2711 return FALSE;
2713 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2714 if (pFT_Library_Version)
2715 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2717 if (FT_Version.major<=0)
2719 FT_Version.major=2;
2720 FT_Version.minor=0;
2721 FT_Version.patch=5;
2723 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2724 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2725 ((FT_Version.minor << 8) & 0x00ff00) |
2726 ((FT_Version.patch ) & 0x0000ff);
2728 return TRUE;
2730 sym_not_found:
2731 WINE_MESSAGE(
2732 "Wine cannot find certain functions that it needs inside the FreeType\n"
2733 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2734 "FreeType to at least version 2.0.5.\n"
2735 "http://www.freetype.org\n");
2736 wine_dlclose(ft_handle, NULL, 0);
2737 ft_handle = NULL;
2738 return FALSE;
2741 /*************************************************************
2742 * WineEngInit
2744 * Initialize FreeType library and create a list of available faces
2746 BOOL WineEngInit(void)
2748 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2749 static const WCHAR pathW[] = {'P','a','t','h',0};
2750 HKEY hkey;
2751 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2752 WCHAR windowsdir[MAX_PATH];
2753 char *unixname;
2754 HANDLE font_mutex;
2755 const char *data_dir;
2757 TRACE("\n");
2759 /* update locale dependent font info in registry */
2760 update_font_info();
2762 if(!init_freetype()) return FALSE;
2764 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2765 ERR("Failed to create font mutex\n");
2766 return FALSE;
2768 WaitForSingleObject(font_mutex, INFINITE);
2770 delete_external_font_keys();
2772 /* load the system bitmap fonts */
2773 load_system_fonts();
2775 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2776 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2777 strcatW(windowsdir, fontsW);
2778 if((unixname = wine_get_unix_file_name(windowsdir)))
2780 ReadFontDir(unixname, FALSE);
2781 HeapFree(GetProcessHeap(), 0, unixname);
2784 /* load the system truetype fonts */
2785 data_dir = wine_get_data_dir();
2786 if (!data_dir) data_dir = wine_get_build_dir();
2787 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2788 strcpy(unixname, data_dir);
2789 strcat(unixname, "/fonts/");
2790 ReadFontDir(unixname, TRUE);
2791 HeapFree(GetProcessHeap(), 0, unixname);
2794 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2795 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2796 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2797 will skip these. */
2798 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2799 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2800 &hkey) == ERROR_SUCCESS) {
2801 LPWSTR data, valueW;
2802 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2803 &valuelen, &datalen, NULL, NULL);
2805 valuelen++; /* returned value doesn't include room for '\0' */
2806 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2807 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2808 if (valueW && data)
2810 dlen = datalen * sizeof(WCHAR);
2811 vlen = valuelen;
2812 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2813 &dlen) == ERROR_SUCCESS) {
2814 if(data[0] && (data[1] == ':'))
2816 if((unixname = wine_get_unix_file_name(data)))
2818 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2819 HeapFree(GetProcessHeap(), 0, unixname);
2822 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2824 WCHAR pathW[MAX_PATH];
2825 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2826 BOOL added = FALSE;
2828 sprintfW(pathW, fmtW, windowsdir, data);
2829 if((unixname = wine_get_unix_file_name(pathW)))
2831 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2832 HeapFree(GetProcessHeap(), 0, unixname);
2834 if (!added)
2835 load_font_from_data_dir(data);
2837 /* reset dlen and vlen */
2838 dlen = datalen;
2839 vlen = valuelen;
2842 HeapFree(GetProcessHeap(), 0, data);
2843 HeapFree(GetProcessHeap(), 0, valueW);
2844 RegCloseKey(hkey);
2847 load_fontconfig_fonts();
2849 /* then look in any directories that we've specified in the config file */
2850 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2851 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2853 DWORD len;
2854 LPWSTR valueW;
2855 LPSTR valueA, ptr;
2857 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2859 len += sizeof(WCHAR);
2860 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2861 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2863 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2864 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2865 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2866 TRACE( "got font path %s\n", debugstr_a(valueA) );
2867 ptr = valueA;
2868 while (ptr)
2870 LPSTR next = strchr( ptr, ':' );
2871 if (next) *next++ = 0;
2872 ReadFontDir( ptr, TRUE );
2873 ptr = next;
2875 HeapFree( GetProcessHeap(), 0, valueA );
2877 HeapFree( GetProcessHeap(), 0, valueW );
2879 RegCloseKey(hkey);
2882 DumpFontList();
2883 LoadSubstList();
2884 DumpSubstList();
2885 LoadReplaceList();
2886 update_reg_entries();
2888 update_system_links();
2889 init_system_links();
2891 ReleaseMutex(font_mutex);
2892 return TRUE;
2896 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2898 TT_OS2 *pOS2;
2899 TT_HoriHeader *pHori;
2901 LONG ppem;
2903 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2904 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2906 if(height == 0) height = 16;
2908 /* Calc. height of EM square:
2910 * For +ve lfHeight we have
2911 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2912 * Re-arranging gives:
2913 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2915 * For -ve lfHeight we have
2916 * |lfHeight| = ppem
2917 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2918 * with il = winAscent + winDescent - units_per_em]
2922 if(height > 0) {
2923 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2924 ppem = MulDiv(ft_face->units_per_EM, height,
2925 pHori->Ascender - pHori->Descender);
2926 else
2927 ppem = MulDiv(ft_face->units_per_EM, height,
2928 pOS2->usWinAscent + pOS2->usWinDescent);
2930 else
2931 ppem = -height;
2933 return ppem;
2936 static struct font_mapping *map_font_file( const char *name )
2938 struct font_mapping *mapping;
2939 struct stat st;
2940 int fd;
2942 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2943 if (fstat( fd, &st ) == -1) goto error;
2945 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2947 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2949 mapping->refcount++;
2950 close( fd );
2951 return mapping;
2954 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2955 goto error;
2957 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2958 close( fd );
2960 if (mapping->data == MAP_FAILED)
2962 HeapFree( GetProcessHeap(), 0, mapping );
2963 return NULL;
2965 mapping->refcount = 1;
2966 mapping->dev = st.st_dev;
2967 mapping->ino = st.st_ino;
2968 mapping->size = st.st_size;
2969 list_add_tail( &mappings_list, &mapping->entry );
2970 return mapping;
2972 error:
2973 close( fd );
2974 return NULL;
2977 static void unmap_font_file( struct font_mapping *mapping )
2979 if (!--mapping->refcount)
2981 list_remove( &mapping->entry );
2982 munmap( mapping->data, mapping->size );
2983 HeapFree( GetProcessHeap(), 0, mapping );
2987 static LONG load_VDMX(GdiFont*, LONG);
2989 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2991 FT_Error err;
2992 FT_Face ft_face;
2993 void *data_ptr;
2994 DWORD data_size;
2996 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2998 if (face->file)
3000 if (!(font->mapping = map_font_file( face->file )))
3002 WARN("failed to map %s\n", debugstr_a(face->file));
3003 return 0;
3005 data_ptr = font->mapping->data;
3006 data_size = font->mapping->size;
3008 else
3010 data_ptr = face->font_data_ptr;
3011 data_size = face->font_data_size;
3014 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3015 if(err) {
3016 ERR("FT_New_Face rets %d\n", err);
3017 return 0;
3020 /* set it here, as load_VDMX needs it */
3021 font->ft_face = ft_face;
3023 if(FT_IS_SCALABLE(ft_face)) {
3024 /* load the VDMX table if we have one */
3025 font->ppem = load_VDMX(font, height);
3026 if(font->ppem == 0)
3027 font->ppem = calc_ppem_for_height(ft_face, height);
3028 TRACE("height %d => ppem %d\n", height, font->ppem);
3030 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3031 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3032 } else {
3033 font->ppem = height;
3034 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3035 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3037 return ft_face;
3041 static int get_nearest_charset(Face *face, int *cp)
3043 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3044 a single face with the requested charset. The idea is to check if
3045 the selected font supports the current ANSI codepage, if it does
3046 return the corresponding charset, else return the first charset */
3048 CHARSETINFO csi;
3049 int acp = GetACP(), i;
3050 DWORD fs0;
3052 *cp = acp;
3053 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3054 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3055 return csi.ciCharset;
3057 for(i = 0; i < 32; i++) {
3058 fs0 = 1L << i;
3059 if(face->fs.fsCsb[0] & fs0) {
3060 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3061 *cp = csi.ciACP;
3062 return csi.ciCharset;
3064 else
3065 FIXME("TCI failing on %x\n", fs0);
3069 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3070 face->fs.fsCsb[0], face->file);
3071 *cp = acp;
3072 return DEFAULT_CHARSET;
3075 static GdiFont *alloc_font(void)
3077 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3078 ret->gmsize = 1;
3079 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3080 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3081 ret->potm = NULL;
3082 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3083 ret->total_kern_pairs = (DWORD)-1;
3084 ret->kern_pairs = NULL;
3085 list_init(&ret->hfontlist);
3086 list_init(&ret->child_fonts);
3087 return ret;
3090 static void free_font(GdiFont *font)
3092 struct list *cursor, *cursor2;
3093 DWORD i;
3095 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3097 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3098 list_remove(cursor);
3099 if(child->font)
3100 free_font(child->font);
3101 HeapFree(GetProcessHeap(), 0, child);
3104 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3106 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3107 DeleteObject(hfontlist->hfont);
3108 list_remove(&hfontlist->entry);
3109 HeapFree(GetProcessHeap(), 0, hfontlist);
3112 if (font->ft_face) pFT_Done_Face(font->ft_face);
3113 if (font->mapping) unmap_font_file( font->mapping );
3114 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3115 HeapFree(GetProcessHeap(), 0, font->potm);
3116 HeapFree(GetProcessHeap(), 0, font->name);
3117 for (i = 0; i < font->gmsize; i++)
3118 HeapFree(GetProcessHeap(),0,font->gm[i]);
3119 HeapFree(GetProcessHeap(), 0, font->gm);
3120 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3121 HeapFree(GetProcessHeap(), 0, font);
3125 /*************************************************************
3126 * load_VDMX
3128 * load the vdmx entry for the specified height
3131 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3132 ( ( (FT_ULong)_x4 << 24 ) | \
3133 ( (FT_ULong)_x3 << 16 ) | \
3134 ( (FT_ULong)_x2 << 8 ) | \
3135 (FT_ULong)_x1 )
3137 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3139 typedef struct {
3140 BYTE bCharSet;
3141 BYTE xRatio;
3142 BYTE yStartRatio;
3143 BYTE yEndRatio;
3144 } Ratios;
3146 typedef struct {
3147 WORD recs;
3148 BYTE startsz;
3149 BYTE endsz;
3150 } VDMX_group;
3152 static LONG load_VDMX(GdiFont *font, LONG height)
3154 WORD hdr[3], tmp;
3155 VDMX_group group;
3156 BYTE devXRatio, devYRatio;
3157 USHORT numRecs, numRatios;
3158 DWORD result, offset = -1;
3159 LONG ppem = 0;
3160 int i;
3162 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3164 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3165 return ppem;
3167 /* FIXME: need the real device aspect ratio */
3168 devXRatio = 1;
3169 devYRatio = 1;
3171 numRecs = GET_BE_WORD(hdr[1]);
3172 numRatios = GET_BE_WORD(hdr[2]);
3174 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3175 for(i = 0; i < numRatios; i++) {
3176 Ratios ratio;
3178 offset = (3 * 2) + (i * sizeof(Ratios));
3179 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3180 offset = -1;
3182 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3184 if((ratio.xRatio == 0 &&
3185 ratio.yStartRatio == 0 &&
3186 ratio.yEndRatio == 0) ||
3187 (devXRatio == ratio.xRatio &&
3188 devYRatio >= ratio.yStartRatio &&
3189 devYRatio <= ratio.yEndRatio))
3191 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3192 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3193 offset = GET_BE_WORD(tmp);
3194 break;
3198 if(offset == -1) {
3199 FIXME("No suitable ratio found\n");
3200 return ppem;
3203 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3204 USHORT recs;
3205 BYTE startsz, endsz;
3206 WORD *vTable;
3208 recs = GET_BE_WORD(group.recs);
3209 startsz = group.startsz;
3210 endsz = group.endsz;
3212 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3214 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3215 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3216 if(result == GDI_ERROR) {
3217 FIXME("Failed to retrieve vTable\n");
3218 goto end;
3221 if(height > 0) {
3222 for(i = 0; i < recs; i++) {
3223 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3224 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3225 ppem = GET_BE_WORD(vTable[i * 3]);
3227 if(yMax + -yMin == height) {
3228 font->yMax = yMax;
3229 font->yMin = yMin;
3230 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3231 break;
3233 if(yMax + -yMin > height) {
3234 if(--i < 0) {
3235 ppem = 0;
3236 goto end; /* failed */
3238 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3239 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3240 ppem = GET_BE_WORD(vTable[i * 3]);
3241 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3242 break;
3245 if(!font->yMax) {
3246 ppem = 0;
3247 TRACE("ppem not found for height %d\n", height);
3250 end:
3251 HeapFree(GetProcessHeap(), 0, vTable);
3254 return ppem;
3257 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3259 if(font->font_desc.hash != fd->hash) return TRUE;
3260 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3261 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3262 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3263 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3266 static void calc_hash(FONT_DESC *pfd)
3268 DWORD hash = 0, *ptr, two_chars;
3269 WORD *pwc;
3270 unsigned int i;
3272 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3273 hash ^= *ptr;
3274 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3275 hash ^= *ptr;
3276 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3277 two_chars = *ptr;
3278 pwc = (WCHAR *)&two_chars;
3279 if(!*pwc) break;
3280 *pwc = toupperW(*pwc);
3281 pwc++;
3282 *pwc = toupperW(*pwc);
3283 hash ^= two_chars;
3284 if(!*pwc) break;
3286 hash ^= !pfd->can_use_bitmap;
3287 pfd->hash = hash;
3288 return;
3291 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3293 GdiFont *ret;
3294 FONT_DESC fd;
3295 HFONTLIST *hflist;
3296 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3298 fd.lf = *plf;
3299 fd.matrix = *pmat;
3300 fd.can_use_bitmap = can_use_bitmap;
3301 calc_hash(&fd);
3303 /* try the child list */
3304 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3305 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3306 if(!fontcmp(ret, &fd)) {
3307 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3308 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3309 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3310 if(hflist->hfont == hfont)
3311 return ret;
3316 /* try the in-use list */
3317 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3318 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3319 if(!fontcmp(ret, &fd)) {
3320 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3321 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3322 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3323 if(hflist->hfont == hfont)
3324 return ret;
3326 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3327 hflist->hfont = hfont;
3328 list_add_head(&ret->hfontlist, &hflist->entry);
3329 return ret;
3333 /* then the unused list */
3334 font_elem_ptr = list_head(&unused_gdi_font_list);
3335 while(font_elem_ptr) {
3336 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3337 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3338 if(!fontcmp(ret, &fd)) {
3339 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3340 assert(list_empty(&ret->hfontlist));
3341 TRACE("Found %p in unused list\n", ret);
3342 list_remove(&ret->entry);
3343 list_add_head(&gdi_font_list, &ret->entry);
3344 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3345 hflist->hfont = hfont;
3346 list_add_head(&ret->hfontlist, &hflist->entry);
3347 return ret;
3350 return NULL;
3353 static void add_to_cache(GdiFont *font)
3355 static DWORD cache_num = 1;
3357 font->cache_num = cache_num++;
3358 list_add_head(&gdi_font_list, &font->entry);
3361 /*************************************************************
3362 * create_child_font_list
3364 static BOOL create_child_font_list(GdiFont *font)
3366 BOOL ret = FALSE;
3367 SYSTEM_LINKS *font_link;
3368 CHILD_FONT *font_link_entry, *new_child;
3369 FontSubst *psub;
3370 WCHAR* font_name;
3372 psub = get_font_subst(&font_subst_list, font->name, -1);
3373 font_name = psub ? psub->to.name : font->name;
3374 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3376 if(!strcmpiW(font_link->font_name, font_name))
3378 TRACE("found entry in system list\n");
3379 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3381 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3382 new_child->face = font_link_entry->face;
3383 new_child->font = NULL;
3384 list_add_tail(&font->child_fonts, &new_child->entry);
3385 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3387 ret = TRUE;
3388 break;
3392 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3393 * Sans Serif. This is how asian windows get default fallbacks for fonts
3395 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3396 font->charset != OEM_CHARSET &&
3397 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3398 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3400 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3402 TRACE("found entry in default fallback list\n");
3403 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3405 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3406 new_child->face = font_link_entry->face;
3407 new_child->font = NULL;
3408 list_add_tail(&font->child_fonts, &new_child->entry);
3409 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3411 ret = TRUE;
3412 break;
3416 return ret;
3419 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3421 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3423 if (pFT_Set_Charmap)
3425 FT_Int i;
3426 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3428 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3430 for (i = 0; i < ft_face->num_charmaps; i++)
3432 if (ft_face->charmaps[i]->encoding == encoding)
3434 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3435 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3437 switch (ft_face->charmaps[i]->platform_id)
3439 default:
3440 cmap_def = ft_face->charmaps[i];
3441 break;
3442 case 0: /* Apple Unicode */
3443 cmap0 = ft_face->charmaps[i];
3444 break;
3445 case 1: /* Macintosh */
3446 cmap1 = ft_face->charmaps[i];
3447 break;
3448 case 2: /* ISO */
3449 cmap2 = ft_face->charmaps[i];
3450 break;
3451 case 3: /* Microsoft */
3452 cmap3 = ft_face->charmaps[i];
3453 break;
3457 if (cmap3) /* prefer Microsoft cmap table */
3458 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3459 else if (cmap1)
3460 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3461 else if (cmap2)
3462 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3463 else if (cmap0)
3464 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3465 else if (cmap_def)
3466 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3468 return ft_err == FT_Err_Ok;
3471 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3474 /*************************************************************
3475 * WineEngCreateFontInstance
3478 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3480 GdiFont *ret;
3481 Face *face, *best, *best_bitmap;
3482 Family *family, *last_resort_family;
3483 struct list *family_elem_ptr, *face_elem_ptr;
3484 INT height, width = 0;
3485 unsigned int score = 0, new_score;
3486 signed int diff = 0, newdiff;
3487 BOOL bd, it, can_use_bitmap;
3488 LOGFONTW lf;
3489 CHARSETINFO csi;
3490 HFONTLIST *hflist;
3491 FMAT2 dcmat;
3492 FontSubst *psub = NULL;
3494 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3495 lf.lfWidth = abs(lf.lfWidth);
3497 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3499 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3500 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3501 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3502 lf.lfEscapement);
3504 if(dc->GraphicsMode == GM_ADVANCED)
3505 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3506 else
3508 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3509 font scaling abilities. */
3510 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3511 dcmat.eM21 = dcmat.eM12 = 0;
3514 /* Try to avoid not necessary glyph transformations */
3515 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3517 lf.lfHeight *= fabs(dcmat.eM11);
3518 lf.lfWidth *= fabs(dcmat.eM11);
3519 dcmat.eM11 = dcmat.eM22 = 1.0;
3522 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3523 dcmat.eM21, dcmat.eM22);
3525 GDI_CheckNotLock();
3526 EnterCriticalSection( &freetype_cs );
3528 /* check the cache first */
3529 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3530 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3531 LeaveCriticalSection( &freetype_cs );
3532 return ret;
3535 TRACE("not in cache\n");
3536 if(list_empty(&font_list)) /* No fonts installed */
3538 TRACE("No fonts installed\n");
3539 LeaveCriticalSection( &freetype_cs );
3540 return NULL;
3543 ret = alloc_font();
3545 ret->font_desc.matrix = dcmat;
3546 ret->font_desc.lf = lf;
3547 ret->font_desc.can_use_bitmap = can_use_bitmap;
3548 calc_hash(&ret->font_desc);
3549 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3550 hflist->hfont = hfont;
3551 list_add_head(&ret->hfontlist, &hflist->entry);
3553 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3554 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3555 original value lfCharSet. Note this is a special case for
3556 Symbol and doesn't happen at least for "Wingdings*" */
3558 if(!strcmpiW(lf.lfFaceName, SymbolW))
3559 lf.lfCharSet = SYMBOL_CHARSET;
3561 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3562 switch(lf.lfCharSet) {
3563 case DEFAULT_CHARSET:
3564 csi.fs.fsCsb[0] = 0;
3565 break;
3566 default:
3567 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3568 csi.fs.fsCsb[0] = 0;
3569 break;
3573 family = NULL;
3574 if(lf.lfFaceName[0] != '\0') {
3575 SYSTEM_LINKS *font_link;
3576 CHILD_FONT *font_link_entry;
3577 LPWSTR FaceName = lf.lfFaceName;
3580 * Check for a leading '@' this signals that the font is being
3581 * requested in tategaki mode (vertical writing substitution) but
3582 * does not affect the fontface that is to be selected.
3584 if (lf.lfFaceName[0]=='@')
3585 FaceName = &lf.lfFaceName[1];
3587 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3589 if(psub) {
3590 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3591 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3592 if (psub->to.charset != -1)
3593 lf.lfCharSet = psub->to.charset;
3596 /* We want a match on name and charset or just name if
3597 charset was DEFAULT_CHARSET. If the latter then
3598 we fixup the returned charset later in get_nearest_charset
3599 where we'll either use the charset of the current ansi codepage
3600 or if that's unavailable the first charset that the font supports.
3602 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3603 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3604 if (!strcmpiW(family->FamilyName, FaceName) ||
3605 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3607 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3608 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3609 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3610 if(face->scalable || can_use_bitmap)
3611 goto found;
3616 /* Search by full face name. */
3617 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3618 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3619 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3620 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3621 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3622 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3624 if(face->scalable || can_use_bitmap)
3625 goto found_face;
3631 * Try check the SystemLink list first for a replacement font.
3632 * We may find good replacements there.
3634 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3636 if(!strcmpiW(font_link->font_name, FaceName) ||
3637 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3639 TRACE("found entry in system list\n");
3640 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3642 face = font_link_entry->face;
3643 family = face->family;
3644 if(csi.fs.fsCsb[0] &
3645 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3647 if(face->scalable || can_use_bitmap)
3648 goto found;
3655 psub = NULL; /* substitution is no more relevant */
3657 /* If requested charset was DEFAULT_CHARSET then try using charset
3658 corresponding to the current ansi codepage */
3659 if (!csi.fs.fsCsb[0])
3661 INT acp = GetACP();
3662 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3663 FIXME("TCI failed on codepage %d\n", acp);
3664 csi.fs.fsCsb[0] = 0;
3665 } else
3666 lf.lfCharSet = csi.ciCharset;
3669 /* Face families are in the top 4 bits of lfPitchAndFamily,
3670 so mask with 0xF0 before testing */
3672 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3673 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3674 strcpyW(lf.lfFaceName, defFixed);
3675 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3676 strcpyW(lf.lfFaceName, defSerif);
3677 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3678 strcpyW(lf.lfFaceName, defSans);
3679 else
3680 strcpyW(lf.lfFaceName, defSans);
3681 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3682 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3683 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3684 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3685 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3686 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3687 if(face->scalable || can_use_bitmap)
3688 goto found;
3693 last_resort_family = NULL;
3694 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3695 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3696 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3697 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3698 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3699 if(face->scalable)
3700 goto found;
3701 if(can_use_bitmap && !last_resort_family)
3702 last_resort_family = family;
3707 if(last_resort_family) {
3708 family = last_resort_family;
3709 csi.fs.fsCsb[0] = 0;
3710 goto found;
3713 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3714 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3715 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3716 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3717 if(face->scalable) {
3718 csi.fs.fsCsb[0] = 0;
3719 WARN("just using first face for now\n");
3720 goto found;
3722 if(can_use_bitmap && !last_resort_family)
3723 last_resort_family = family;
3726 if(!last_resort_family) {
3727 FIXME("can't find a single appropriate font - bailing\n");
3728 free_font(ret);
3729 LeaveCriticalSection( &freetype_cs );
3730 return NULL;
3733 WARN("could only find a bitmap font - this will probably look awful!\n");
3734 family = last_resort_family;
3735 csi.fs.fsCsb[0] = 0;
3737 found:
3738 it = lf.lfItalic ? 1 : 0;
3739 bd = lf.lfWeight > 550 ? 1 : 0;
3741 height = lf.lfHeight;
3743 face = best = best_bitmap = NULL;
3744 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3746 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3748 BOOL italic, bold;
3750 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3751 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3752 new_score = (italic ^ it) + (bold ^ bd);
3753 if(!best || new_score <= score)
3755 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3756 italic, bold, it, bd);
3757 score = new_score;
3758 best = face;
3759 if(best->scalable && score == 0) break;
3760 if(!best->scalable)
3762 if(height > 0)
3763 newdiff = height - (signed int)(best->size.height);
3764 else
3765 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3766 if(!best_bitmap || new_score < score ||
3767 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3769 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3770 diff = newdiff;
3771 best_bitmap = best;
3772 if(score == 0 && diff == 0) break;
3778 if(best)
3779 face = best->scalable ? best : best_bitmap;
3780 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3781 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3783 found_face:
3784 height = lf.lfHeight;
3786 ret->fs = face->fs;
3788 if(csi.fs.fsCsb[0]) {
3789 ret->charset = lf.lfCharSet;
3790 ret->codepage = csi.ciACP;
3792 else
3793 ret->charset = get_nearest_charset(face, &ret->codepage);
3795 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3796 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3798 ret->aveWidth = height ? lf.lfWidth : 0;
3800 if(!face->scalable) {
3801 /* Windows uses integer scaling factors for bitmap fonts */
3802 INT scale, scaled_height;
3803 GdiFont *cachedfont;
3805 /* FIXME: rotation of bitmap fonts is ignored */
3806 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3807 if (ret->aveWidth)
3808 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3809 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3810 dcmat.eM11 = dcmat.eM22 = 1.0;
3811 /* As we changed the matrix, we need to search the cache for the font again,
3812 * otherwise we might explode the cache. */
3813 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3814 TRACE("Found cached font after non-scalable matrix rescale!\n");
3815 free_font( ret );
3816 LeaveCriticalSection( &freetype_cs );
3817 return cachedfont;
3819 calc_hash(&ret->font_desc);
3821 if (height != 0) height = diff;
3822 height += face->size.height;
3824 scale = (height + face->size.height - 1) / face->size.height;
3825 scaled_height = scale * face->size.height;
3826 /* Only jump to the next height if the difference <= 25% original height */
3827 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3828 /* The jump between unscaled and doubled is delayed by 1 */
3829 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3830 ret->scale_y = scale;
3832 width = face->size.x_ppem >> 6;
3833 height = face->size.y_ppem >> 6;
3835 else
3836 ret->scale_y = 1.0;
3837 TRACE("font scale y: %f\n", ret->scale_y);
3839 ret->ft_face = OpenFontFace(ret, face, width, height);
3841 if (!ret->ft_face)
3843 free_font( ret );
3844 LeaveCriticalSection( &freetype_cs );
3845 return 0;
3848 ret->ntmFlags = face->ntmFlags;
3850 if (ret->charset == SYMBOL_CHARSET &&
3851 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3852 /* No ops */
3854 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3855 /* No ops */
3857 else {
3858 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3861 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3862 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3863 ret->underline = lf.lfUnderline ? 0xff : 0;
3864 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3865 create_child_font_list(ret);
3867 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3869 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3870 if (length != GDI_ERROR)
3872 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3873 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3874 TRACE("Loaded GSUB table of %i bytes\n",length);
3878 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3880 add_to_cache(ret);
3881 LeaveCriticalSection( &freetype_cs );
3882 return ret;
3885 static void dump_gdi_font_list(void)
3887 GdiFont *gdiFont;
3888 struct list *elem_ptr;
3890 TRACE("---------- gdiFont Cache ----------\n");
3891 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3892 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3893 TRACE("gdiFont=%p %s %d\n",
3894 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3897 TRACE("---------- Unused gdiFont Cache ----------\n");
3898 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3899 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3900 TRACE("gdiFont=%p %s %d\n",
3901 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3904 TRACE("---------- Child gdiFont Cache ----------\n");
3905 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3906 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3907 TRACE("gdiFont=%p %s %d\n",
3908 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3912 /*************************************************************
3913 * WineEngDestroyFontInstance
3915 * free the gdiFont associated with this handle
3918 BOOL WineEngDestroyFontInstance(HFONT handle)
3920 GdiFont *gdiFont;
3921 HFONTLIST *hflist;
3922 BOOL ret = FALSE;
3923 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3924 int i = 0;
3926 GDI_CheckNotLock();
3927 EnterCriticalSection( &freetype_cs );
3929 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3931 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3932 while(hfontlist_elem_ptr) {
3933 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3934 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3935 if(hflist->hfont == handle) {
3936 TRACE("removing child font %p from child list\n", gdiFont);
3937 list_remove(&gdiFont->entry);
3938 LeaveCriticalSection( &freetype_cs );
3939 return TRUE;
3944 TRACE("destroying hfont=%p\n", handle);
3945 if(TRACE_ON(font))
3946 dump_gdi_font_list();
3948 font_elem_ptr = list_head(&gdi_font_list);
3949 while(font_elem_ptr) {
3950 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3951 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3953 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3954 while(hfontlist_elem_ptr) {
3955 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3956 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3957 if(hflist->hfont == handle) {
3958 list_remove(&hflist->entry);
3959 HeapFree(GetProcessHeap(), 0, hflist);
3960 ret = TRUE;
3963 if(list_empty(&gdiFont->hfontlist)) {
3964 TRACE("Moving to Unused list\n");
3965 list_remove(&gdiFont->entry);
3966 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3971 font_elem_ptr = list_head(&unused_gdi_font_list);
3972 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3973 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3974 while(font_elem_ptr) {
3975 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3976 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3977 TRACE("freeing %p\n", gdiFont);
3978 list_remove(&gdiFont->entry);
3979 free_font(gdiFont);
3981 LeaveCriticalSection( &freetype_cs );
3982 return ret;
3985 /***************************************************
3986 * create_enum_charset_list
3988 * This function creates charset enumeration list because in DEFAULT_CHARSET
3989 * case, the ANSI codepage's charset takes precedence over other charsets.
3990 * This function works as a filter other than DEFAULT_CHARSET case.
3992 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
3994 CHARSETINFO csi;
3995 DWORD n = 0;
3997 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
3998 csi.fs.fsCsb[0] != 0) {
3999 list->element[n].mask = csi.fs.fsCsb[0];
4000 list->element[n].charset = csi.ciCharset;
4001 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4002 n++;
4004 else { /* charset is DEFAULT_CHARSET or invalid. */
4005 INT acp, i;
4007 /* Set the current codepage's charset as the first element. */
4008 acp = GetACP();
4009 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4010 csi.fs.fsCsb[0] != 0) {
4011 list->element[n].mask = csi.fs.fsCsb[0];
4012 list->element[n].charset = csi.ciCharset;
4013 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4014 n++;
4017 /* Fill out left elements. */
4018 for (i = 0; i < 32; i++) {
4019 FONTSIGNATURE fs;
4020 fs.fsCsb[0] = 1L << i;
4021 fs.fsCsb[1] = 0;
4022 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4023 continue; /* skip, already added. */
4024 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4025 continue; /* skip, this is an invalid fsCsb bit. */
4027 list->element[n].mask = fs.fsCsb[0];
4028 list->element[n].charset = csi.ciCharset;
4029 list->element[n].name = ElfScriptsW[i];
4030 n++;
4033 list->total = n;
4035 return n;
4038 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4039 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4041 GdiFont *font;
4042 LONG width, height;
4044 if (face->cached_enum_data)
4046 TRACE("Cached\n");
4047 *pelf = face->cached_enum_data->elf;
4048 *pntm = face->cached_enum_data->ntm;
4049 *ptype = face->cached_enum_data->type;
4050 return;
4053 font = alloc_font();
4055 if(face->scalable) {
4056 height = -2048; /* 2048 is the most common em size */
4057 width = 0;
4058 } else {
4059 height = face->size.y_ppem >> 6;
4060 width = face->size.x_ppem >> 6;
4062 font->scale_y = 1.0;
4064 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4066 free_font(font);
4067 return;
4070 font->name = strdupW(face->family->FamilyName);
4071 font->ntmFlags = face->ntmFlags;
4073 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4075 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4077 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4079 lstrcpynW(pelf->elfLogFont.lfFaceName,
4080 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4081 LF_FACESIZE);
4082 lstrcpynW(pelf->elfFullName,
4083 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4084 LF_FULLFACESIZE);
4085 lstrcpynW(pelf->elfStyle,
4086 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4087 LF_FACESIZE);
4089 else
4091 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4093 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4095 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4096 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4097 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4100 pntm->ntmTm.ntmFlags = face->ntmFlags;
4101 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4102 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4103 pntm->ntmFontSig = face->fs;
4105 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4107 pelf->elfLogFont.lfEscapement = 0;
4108 pelf->elfLogFont.lfOrientation = 0;
4109 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4110 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4111 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4112 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4113 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4114 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4115 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4116 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4117 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4118 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4119 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4121 *ptype = 0;
4122 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4123 *ptype |= TRUETYPE_FONTTYPE;
4124 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4125 *ptype |= DEVICE_FONTTYPE;
4126 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4127 *ptype |= RASTER_FONTTYPE;
4129 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4130 if (face->cached_enum_data)
4132 face->cached_enum_data->elf = *pelf;
4133 face->cached_enum_data->ntm = *pntm;
4134 face->cached_enum_data->type = *ptype;
4137 free_font(font);
4140 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4142 struct list *face_elem_ptr;
4144 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4146 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4148 static const WCHAR spaceW[] = { ' ',0 };
4149 WCHAR full_family_name[LF_FULLFACESIZE];
4150 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4152 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4154 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4155 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4156 continue;
4159 strcpyW(full_family_name, family->FamilyName);
4160 strcatW(full_family_name, spaceW);
4161 strcatW(full_family_name, face->StyleName);
4162 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4165 return FALSE;
4168 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4170 static const WCHAR spaceW[] = { ' ',0 };
4171 WCHAR full_family_name[LF_FULLFACESIZE];
4173 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4175 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4177 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4178 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4179 return FALSE;
4182 strcpyW(full_family_name, face->family->FamilyName);
4183 strcatW(full_family_name, spaceW);
4184 strcatW(full_family_name, face->StyleName);
4185 return !strcmpiW(lf->lfFaceName, full_family_name);
4188 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4189 FONTENUMPROCW proc, LPARAM lparam)
4191 ENUMLOGFONTEXW elf;
4192 NEWTEXTMETRICEXW ntm;
4193 DWORD type = 0;
4194 int i;
4196 GetEnumStructs(face, &elf, &ntm, &type);
4197 for(i = 0; i < list->total; i++) {
4198 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4199 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4200 strcpyW(elf.elfScript, OEM_DOSW);
4201 i = 32; /* break out of loop */
4202 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4203 continue;
4204 else {
4205 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4206 if(list->element[i].name)
4207 strcpyW(elf.elfScript, list->element[i].name);
4208 else
4209 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4211 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4212 debugstr_w(elf.elfLogFont.lfFaceName),
4213 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4214 list->element[i].charset, type, debugstr_w(elf.elfScript),
4215 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4216 ntm.ntmTm.ntmFlags);
4217 /* release section before callback (FIXME) */
4218 LeaveCriticalSection( &freetype_cs );
4219 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4220 EnterCriticalSection( &freetype_cs );
4222 return TRUE;
4225 /*************************************************************
4226 * WineEngEnumFonts
4229 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4231 Family *family;
4232 Face *face;
4233 struct list *family_elem_ptr, *face_elem_ptr;
4234 LOGFONTW lf;
4235 struct enum_charset_list enum_charsets;
4237 if (!plf)
4239 lf.lfCharSet = DEFAULT_CHARSET;
4240 lf.lfPitchAndFamily = 0;
4241 lf.lfFaceName[0] = 0;
4242 plf = &lf;
4245 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4247 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4249 GDI_CheckNotLock();
4250 EnterCriticalSection( &freetype_cs );
4251 if(plf->lfFaceName[0]) {
4252 FontSubst *psub;
4253 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4255 if(psub) {
4256 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4257 debugstr_w(psub->to.name));
4258 lf = *plf;
4259 strcpyW(lf.lfFaceName, psub->to.name);
4260 plf = &lf;
4263 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4264 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4265 if(family_matches(family, plf)) {
4266 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4267 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4268 if (!face_matches(face, plf)) continue;
4269 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4273 } else {
4274 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4275 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4276 face_elem_ptr = list_head(&family->faces);
4277 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4278 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4281 LeaveCriticalSection( &freetype_cs );
4282 return 1;
4285 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4287 pt->x.value = vec->x >> 6;
4288 pt->x.fract = (vec->x & 0x3f) << 10;
4289 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4290 pt->y.value = vec->y >> 6;
4291 pt->y.fract = (vec->y & 0x3f) << 10;
4292 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4293 return;
4296 /***************************************************
4297 * According to the MSDN documentation on WideCharToMultiByte,
4298 * certain codepages cannot set the default_used parameter.
4299 * This returns TRUE if the codepage can set that parameter, false else
4300 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4302 static BOOL codepage_sets_default_used(UINT codepage)
4304 switch (codepage)
4306 case CP_UTF7:
4307 case CP_UTF8:
4308 case CP_SYMBOL:
4309 return FALSE;
4310 default:
4311 return TRUE;
4316 * GSUB Table handling functions
4319 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4321 const GSUB_CoverageFormat1* cf1;
4323 cf1 = table;
4325 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4327 int count = GET_BE_WORD(cf1->GlyphCount);
4328 int i;
4329 TRACE("Coverage Format 1, %i glyphs\n",count);
4330 for (i = 0; i < count; i++)
4331 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4332 return i;
4333 return -1;
4335 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4337 const GSUB_CoverageFormat2* cf2;
4338 int i;
4339 int count;
4340 cf2 = (const GSUB_CoverageFormat2*)cf1;
4342 count = GET_BE_WORD(cf2->RangeCount);
4343 TRACE("Coverage Format 2, %i ranges\n",count);
4344 for (i = 0; i < count; i++)
4346 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4347 return -1;
4348 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4349 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4351 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4352 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4355 return -1;
4357 else
4358 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4360 return -1;
4363 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4365 const GSUB_ScriptList *script;
4366 const GSUB_Script *deflt = NULL;
4367 int i;
4368 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4370 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4371 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4373 const GSUB_Script *scr;
4374 int offset;
4376 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4377 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4379 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4380 return scr;
4381 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4382 deflt = scr;
4384 return deflt;
4387 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4389 int i;
4390 int offset;
4391 const GSUB_LangSys *Lang;
4393 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4395 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4397 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4398 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4400 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4401 return Lang;
4403 offset = GET_BE_WORD(script->DefaultLangSys);
4404 if (offset)
4406 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4407 return Lang;
4409 return NULL;
4412 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4414 int i;
4415 const GSUB_FeatureList *feature;
4416 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4418 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4419 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4421 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4422 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4424 const GSUB_Feature *feat;
4425 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4426 return feat;
4429 return NULL;
4432 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4434 int i;
4435 int offset;
4436 const GSUB_LookupList *lookup;
4437 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4439 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4440 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4442 const GSUB_LookupTable *look;
4443 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4444 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4445 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4446 if (GET_BE_WORD(look->LookupType) != 1)
4447 FIXME("We only handle SubType 1\n");
4448 else
4450 int j;
4452 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4454 const GSUB_SingleSubstFormat1 *ssf1;
4455 offset = GET_BE_WORD(look->SubTable[j]);
4456 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4457 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4459 int offset = GET_BE_WORD(ssf1->Coverage);
4460 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4461 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4463 TRACE(" Glyph 0x%x ->",glyph);
4464 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4465 TRACE(" 0x%x\n",glyph);
4468 else
4470 const GSUB_SingleSubstFormat2 *ssf2;
4471 INT index;
4472 INT offset;
4474 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4475 offset = GET_BE_WORD(ssf1->Coverage);
4476 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4477 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4478 TRACE(" Coverage index %i\n",index);
4479 if (index != -1)
4481 TRACE(" Glyph is 0x%x ->",glyph);
4482 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4483 TRACE("0x%x\n",glyph);
4489 return glyph;
4492 static const char* get_opentype_script(const GdiFont *font)
4495 * I am not sure if this is the correct way to generate our script tag
4498 switch (font->charset)
4500 case ANSI_CHARSET: return "latn";
4501 case BALTIC_CHARSET: return "latn"; /* ?? */
4502 case CHINESEBIG5_CHARSET: return "hani";
4503 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4504 case GB2312_CHARSET: return "hani";
4505 case GREEK_CHARSET: return "grek";
4506 case HANGUL_CHARSET: return "hang";
4507 case RUSSIAN_CHARSET: return "cyrl";
4508 case SHIFTJIS_CHARSET: return "kana";
4509 case TURKISH_CHARSET: return "latn"; /* ?? */
4510 case VIETNAMESE_CHARSET: return "latn";
4511 case JOHAB_CHARSET: return "latn"; /* ?? */
4512 case ARABIC_CHARSET: return "arab";
4513 case HEBREW_CHARSET: return "hebr";
4514 case THAI_CHARSET: return "thai";
4515 default: return "latn";
4519 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4521 const GSUB_Header *header;
4522 const GSUB_Script *script;
4523 const GSUB_LangSys *language;
4524 const GSUB_Feature *feature;
4526 if (!font->GSUB_Table)
4527 return glyph;
4529 header = font->GSUB_Table;
4531 script = GSUB_get_script_table(header, get_opentype_script(font));
4532 if (!script)
4534 TRACE("Script not found\n");
4535 return glyph;
4537 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4538 if (!language)
4540 TRACE("Language not found\n");
4541 return glyph;
4543 feature = GSUB_get_feature(header, language, "vrt2");
4544 if (!feature)
4545 feature = GSUB_get_feature(header, language, "vert");
4546 if (!feature)
4548 TRACE("vrt2/vert feature not found\n");
4549 return glyph;
4551 return GSUB_apply_feature(header, feature, glyph);
4554 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4556 FT_UInt glyphId;
4558 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4559 WCHAR wc = (WCHAR)glyph;
4560 BOOL default_used;
4561 BOOL *default_used_pointer;
4562 FT_UInt ret;
4563 char buf;
4564 default_used_pointer = NULL;
4565 default_used = FALSE;
4566 if (codepage_sets_default_used(font->codepage))
4567 default_used_pointer = &default_used;
4568 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4569 ret = 0;
4570 else
4571 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4572 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4573 return get_GSUB_vert_glyph(font,ret);
4576 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4578 if (glyph < 0x100) glyph += 0xf000;
4579 /* there is a number of old pre-Unicode "broken" TTFs, which
4580 do have symbols at U+00XX instead of U+f0XX */
4581 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4582 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4584 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4586 return get_GSUB_vert_glyph(font,glyphId);
4589 /*************************************************************
4590 * WineEngGetGlyphIndices
4593 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4594 LPWORD pgi, DWORD flags)
4596 int i;
4597 int default_char = -1;
4599 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4601 for(i = 0; i < count; i++)
4603 pgi[i] = get_glyph_index(font, lpstr[i]);
4604 if (pgi[i] == 0)
4606 if (default_char == -1)
4608 if (FT_IS_SFNT(font->ft_face))
4610 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4611 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4613 else
4615 TEXTMETRICW textm;
4616 WineEngGetTextMetrics(font, &textm);
4617 default_char = textm.tmDefaultChar;
4620 pgi[i] = default_char;
4623 return count;
4626 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4628 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4629 return !memcmp(matrix, &identity, sizeof(FMAT2));
4632 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4634 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4635 return !memcmp(matrix, &identity, sizeof(MAT2));
4638 /*************************************************************
4639 * WineEngGetGlyphOutline
4641 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4642 * except that the first parameter is the HWINEENGFONT of the font in
4643 * question rather than an HDC.
4646 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4647 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4648 const MAT2* lpmat)
4650 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4651 FT_Face ft_face = incoming_font->ft_face;
4652 GdiFont *font = incoming_font;
4653 FT_UInt glyph_index;
4654 DWORD width, height, pitch, needed = 0;
4655 FT_Bitmap ft_bitmap;
4656 FT_Error err;
4657 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4658 FT_Angle angle = 0;
4659 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4660 double widthRatio = 1.0;
4661 FT_Matrix transMat = identityMat;
4662 FT_Matrix transMatUnrotated;
4663 BOOL needsTransform = FALSE;
4664 BOOL tategaki = (font->GSUB_Table != NULL);
4665 UINT original_index;
4667 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4668 buflen, buf, lpmat);
4670 TRACE("font transform %f %f %f %f\n",
4671 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4672 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4674 GDI_CheckNotLock();
4675 EnterCriticalSection( &freetype_cs );
4677 if(format & GGO_GLYPH_INDEX) {
4678 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4679 original_index = glyph;
4680 format &= ~GGO_GLYPH_INDEX;
4681 } else {
4682 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4683 ft_face = font->ft_face;
4684 original_index = glyph_index;
4687 if(format & GGO_UNHINTED) {
4688 load_flags |= FT_LOAD_NO_HINTING;
4689 format &= ~GGO_UNHINTED;
4692 /* tategaki never appears to happen to lower glyph index */
4693 if (glyph_index < TATEGAKI_LOWER_BOUND )
4694 tategaki = FALSE;
4696 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4697 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4698 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4699 font->gmsize * sizeof(GM*));
4700 } else {
4701 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4702 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4704 *lpgm = FONT_GM(font,original_index)->gm;
4705 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4706 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4707 lpgm->gmCellIncX, lpgm->gmCellIncY);
4708 LeaveCriticalSection( &freetype_cs );
4709 return 1; /* FIXME */
4713 if (!font->gm[original_index / GM_BLOCK_SIZE])
4714 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4716 /* Scaling factor */
4717 if (font->aveWidth)
4719 TEXTMETRICW tm;
4721 WineEngGetTextMetrics(font, &tm);
4723 widthRatio = (double)font->aveWidth;
4724 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4726 else
4727 widthRatio = font->scale_y;
4729 /* Scaling transform */
4730 if (widthRatio != 1.0 || font->scale_y != 1.0)
4732 FT_Matrix scaleMat;
4733 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4734 scaleMat.xy = 0;
4735 scaleMat.yx = 0;
4736 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4738 pFT_Matrix_Multiply(&scaleMat, &transMat);
4739 needsTransform = TRUE;
4742 /* Slant transform */
4743 if (font->fake_italic) {
4744 FT_Matrix slantMat;
4746 slantMat.xx = (1 << 16);
4747 slantMat.xy = ((1 << 16) >> 2);
4748 slantMat.yx = 0;
4749 slantMat.yy = (1 << 16);
4750 pFT_Matrix_Multiply(&slantMat, &transMat);
4751 needsTransform = TRUE;
4754 /* Rotation transform */
4755 transMatUnrotated = transMat;
4756 if(font->orientation && !tategaki) {
4757 FT_Matrix rotationMat;
4758 FT_Vector vecAngle;
4759 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4760 pFT_Vector_Unit(&vecAngle, angle);
4761 rotationMat.xx = vecAngle.x;
4762 rotationMat.xy = -vecAngle.y;
4763 rotationMat.yx = -rotationMat.xy;
4764 rotationMat.yy = rotationMat.xx;
4766 pFT_Matrix_Multiply(&rotationMat, &transMat);
4767 needsTransform = TRUE;
4770 /* World transform */
4771 if (!is_identity_FMAT2(&font->font_desc.matrix))
4773 FT_Matrix worldMat;
4774 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4775 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4776 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4777 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4778 pFT_Matrix_Multiply(&worldMat, &transMat);
4779 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4780 needsTransform = TRUE;
4783 /* Extra transformation specified by caller */
4784 if (!is_identity_MAT2(lpmat))
4786 FT_Matrix extraMat;
4787 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4788 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4789 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4790 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4791 pFT_Matrix_Multiply(&extraMat, &transMat);
4792 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4793 needsTransform = TRUE;
4796 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4797 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4798 format == GGO_GRAY8_BITMAP))
4800 load_flags |= FT_LOAD_NO_BITMAP;
4803 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4805 if(err) {
4806 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4807 LeaveCriticalSection( &freetype_cs );
4808 return GDI_ERROR;
4811 if(!needsTransform) {
4812 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4813 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4814 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4816 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4817 bottom = (ft_face->glyph->metrics.horiBearingY -
4818 ft_face->glyph->metrics.height) & -64;
4819 lpgm->gmCellIncX = adv;
4820 lpgm->gmCellIncY = 0;
4821 } else {
4822 INT xc, yc;
4823 FT_Vector vec;
4825 left = right = 0;
4827 for(xc = 0; xc < 2; xc++) {
4828 for(yc = 0; yc < 2; yc++) {
4829 vec.x = (ft_face->glyph->metrics.horiBearingX +
4830 xc * ft_face->glyph->metrics.width);
4831 vec.y = ft_face->glyph->metrics.horiBearingY -
4832 yc * ft_face->glyph->metrics.height;
4833 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4834 pFT_Vector_Transform(&vec, &transMat);
4835 if(xc == 0 && yc == 0) {
4836 left = right = vec.x;
4837 top = bottom = vec.y;
4838 } else {
4839 if(vec.x < left) left = vec.x;
4840 else if(vec.x > right) right = vec.x;
4841 if(vec.y < bottom) bottom = vec.y;
4842 else if(vec.y > top) top = vec.y;
4846 left = left & -64;
4847 right = (right + 63) & -64;
4848 bottom = bottom & -64;
4849 top = (top + 63) & -64;
4851 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4852 vec.x = ft_face->glyph->metrics.horiAdvance;
4853 vec.y = 0;
4854 pFT_Vector_Transform(&vec, &transMat);
4855 lpgm->gmCellIncX = (vec.x+63) >> 6;
4856 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4858 vec.x = ft_face->glyph->metrics.horiAdvance;
4859 vec.y = 0;
4860 pFT_Vector_Transform(&vec, &transMatUnrotated);
4861 adv = (vec.x+63) >> 6;
4864 lsb = left >> 6;
4865 bbx = (right - left) >> 6;
4866 lpgm->gmBlackBoxX = (right - left) >> 6;
4867 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4868 lpgm->gmptGlyphOrigin.x = left >> 6;
4869 lpgm->gmptGlyphOrigin.y = top >> 6;
4871 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4872 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4873 lpgm->gmCellIncX, lpgm->gmCellIncY);
4875 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4876 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4878 FONT_GM(font,original_index)->gm = *lpgm;
4879 FONT_GM(font,original_index)->adv = adv;
4880 FONT_GM(font,original_index)->lsb = lsb;
4881 FONT_GM(font,original_index)->bbx = bbx;
4882 FONT_GM(font,original_index)->init = TRUE;
4885 if(format == GGO_METRICS)
4887 LeaveCriticalSection( &freetype_cs );
4888 return 1; /* FIXME */
4891 if(ft_face->glyph->format != ft_glyph_format_outline &&
4892 (format == GGO_NATIVE || format == GGO_BEZIER ||
4893 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4894 format == GGO_GRAY8_BITMAP))
4896 TRACE("loaded a bitmap\n");
4897 LeaveCriticalSection( &freetype_cs );
4898 return GDI_ERROR;
4901 switch(format) {
4902 case GGO_BITMAP:
4903 width = lpgm->gmBlackBoxX;
4904 height = lpgm->gmBlackBoxY;
4905 pitch = ((width + 31) >> 5) << 2;
4906 needed = pitch * height;
4908 if(!buf || !buflen) break;
4910 switch(ft_face->glyph->format) {
4911 case ft_glyph_format_bitmap:
4913 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4914 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4915 INT h = ft_face->glyph->bitmap.rows;
4916 while(h--) {
4917 memcpy(dst, src, w);
4918 src += ft_face->glyph->bitmap.pitch;
4919 dst += pitch;
4921 break;
4924 case ft_glyph_format_outline:
4925 ft_bitmap.width = width;
4926 ft_bitmap.rows = height;
4927 ft_bitmap.pitch = pitch;
4928 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4929 ft_bitmap.buffer = buf;
4931 if(needsTransform)
4932 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4934 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4936 /* Note: FreeType will only set 'black' bits for us. */
4937 memset(buf, 0, needed);
4938 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4939 break;
4941 default:
4942 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4943 LeaveCriticalSection( &freetype_cs );
4944 return GDI_ERROR;
4946 break;
4948 case GGO_GRAY2_BITMAP:
4949 case GGO_GRAY4_BITMAP:
4950 case GGO_GRAY8_BITMAP:
4951 case WINE_GGO_GRAY16_BITMAP:
4953 unsigned int mult, row, col;
4954 BYTE *start, *ptr;
4956 width = lpgm->gmBlackBoxX;
4957 height = lpgm->gmBlackBoxY;
4958 pitch = (width + 3) / 4 * 4;
4959 needed = pitch * height;
4961 if(!buf || !buflen) break;
4963 switch(ft_face->glyph->format) {
4964 case ft_glyph_format_bitmap:
4966 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4967 INT h = ft_face->glyph->bitmap.rows;
4968 INT x;
4969 memset( buf, 0, needed );
4970 while(h--) {
4971 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
4972 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
4973 src += ft_face->glyph->bitmap.pitch;
4974 dst += pitch;
4976 LeaveCriticalSection( &freetype_cs );
4977 return needed;
4979 case ft_glyph_format_outline:
4981 ft_bitmap.width = width;
4982 ft_bitmap.rows = height;
4983 ft_bitmap.pitch = pitch;
4984 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4985 ft_bitmap.buffer = buf;
4987 if(needsTransform)
4988 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4990 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4992 memset(ft_bitmap.buffer, 0, buflen);
4994 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4996 if(format == GGO_GRAY2_BITMAP)
4997 mult = 4;
4998 else if(format == GGO_GRAY4_BITMAP)
4999 mult = 16;
5000 else if(format == GGO_GRAY8_BITMAP)
5001 mult = 64;
5002 else /* format == WINE_GGO_GRAY16_BITMAP */
5004 LeaveCriticalSection( &freetype_cs );
5005 return needed;
5007 break;
5009 default:
5010 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5011 LeaveCriticalSection( &freetype_cs );
5012 return GDI_ERROR;
5015 start = buf;
5016 for(row = 0; row < height; row++) {
5017 ptr = start;
5018 for(col = 0; col < width; col++, ptr++) {
5019 *ptr = (((int)*ptr) * mult + 128) / 256;
5021 start += pitch;
5023 break;
5026 case WINE_GGO_HRGB_BITMAP:
5027 case WINE_GGO_HBGR_BITMAP:
5028 case WINE_GGO_VRGB_BITMAP:
5029 case WINE_GGO_VBGR_BITMAP:
5030 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5032 switch (ft_face->glyph->format)
5034 case FT_GLYPH_FORMAT_BITMAP:
5036 BYTE *src, *dst;
5037 INT src_pitch, x;
5039 width = lpgm->gmBlackBoxX;
5040 height = lpgm->gmBlackBoxY;
5041 pitch = width * 4;
5042 needed = pitch * height;
5044 if (!buf || !buflen) break;
5046 memset(buf, 0, buflen);
5047 dst = buf;
5048 src = ft_face->glyph->bitmap.buffer;
5049 src_pitch = ft_face->glyph->bitmap.pitch;
5051 height = min( height, ft_face->glyph->bitmap.rows );
5052 while ( height-- )
5054 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5056 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5057 ((unsigned int *)dst)[x] = ~0u;
5059 src += src_pitch;
5060 dst += pitch;
5063 break;
5066 case FT_GLYPH_FORMAT_OUTLINE:
5068 unsigned int *dst;
5069 BYTE *src;
5070 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5071 INT x_shift, y_shift;
5072 BOOL rgb;
5073 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5074 FT_Render_Mode render_mode =
5075 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5076 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5078 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5080 if ( render_mode == FT_RENDER_MODE_LCD)
5082 lpgm->gmBlackBoxX += 2;
5083 lpgm->gmptGlyphOrigin.x -= 1;
5085 else
5087 lpgm->gmBlackBoxY += 2;
5088 lpgm->gmptGlyphOrigin.y += 1;
5092 width = lpgm->gmBlackBoxX;
5093 height = lpgm->gmBlackBoxY;
5094 pitch = width * 4;
5095 needed = pitch * height;
5097 if (!buf || !buflen) break;
5099 memset(buf, 0, buflen);
5100 dst = buf;
5101 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5103 if ( needsTransform )
5104 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5106 if ( pFT_Library_SetLcdFilter )
5107 pFT_Library_SetLcdFilter( library, lcdfilter );
5108 pFT_Render_Glyph (ft_face->glyph, render_mode);
5110 src = ft_face->glyph->bitmap.buffer;
5111 src_pitch = ft_face->glyph->bitmap.pitch;
5112 src_width = ft_face->glyph->bitmap.width;
5113 src_height = ft_face->glyph->bitmap.rows;
5115 if ( render_mode == FT_RENDER_MODE_LCD)
5117 rgb_interval = 1;
5118 hmul = 3;
5119 vmul = 1;
5121 else
5123 rgb_interval = src_pitch;
5124 hmul = 1;
5125 vmul = 3;
5128 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5129 if ( x_shift < 0 ) x_shift = 0;
5130 if ( x_shift + (src_width / hmul) > width )
5131 x_shift = width - (src_width / hmul);
5133 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5134 if ( y_shift < 0 ) y_shift = 0;
5135 if ( y_shift + (src_height / vmul) > height )
5136 y_shift = height - (src_height / vmul);
5138 dst += x_shift + y_shift * ( pitch / 4 );
5139 while ( src_height )
5141 for ( x = 0; x < src_width / hmul; x++ )
5143 if ( rgb )
5145 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5146 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5147 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5148 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5150 else
5152 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5153 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5154 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5155 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5158 src += src_pitch * vmul;
5159 dst += pitch / 4;
5160 src_height -= vmul;
5163 break;
5166 default:
5167 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5168 LeaveCriticalSection ( &freetype_cs );
5169 return GDI_ERROR;
5172 break;
5174 #else
5175 LeaveCriticalSection( &freetype_cs );
5176 return GDI_ERROR;
5177 #endif
5179 case GGO_NATIVE:
5181 int contour, point = 0, first_pt;
5182 FT_Outline *outline = &ft_face->glyph->outline;
5183 TTPOLYGONHEADER *pph;
5184 TTPOLYCURVE *ppc;
5185 DWORD pph_start, cpfx, type;
5187 if(buflen == 0) buf = NULL;
5189 if (needsTransform && buf) {
5190 pFT_Outline_Transform(outline, &transMat);
5193 for(contour = 0; contour < outline->n_contours; contour++) {
5194 pph_start = needed;
5195 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5196 first_pt = point;
5197 if(buf) {
5198 pph->dwType = TT_POLYGON_TYPE;
5199 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5201 needed += sizeof(*pph);
5202 point++;
5203 while(point <= outline->contours[contour]) {
5204 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5205 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5206 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5207 cpfx = 0;
5208 do {
5209 if(buf)
5210 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5211 cpfx++;
5212 point++;
5213 } while(point <= outline->contours[contour] &&
5214 (outline->tags[point] & FT_Curve_Tag_On) ==
5215 (outline->tags[point-1] & FT_Curve_Tag_On));
5216 /* At the end of a contour Windows adds the start point, but
5217 only for Beziers */
5218 if(point > outline->contours[contour] &&
5219 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5220 if(buf)
5221 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5222 cpfx++;
5223 } else if(point <= outline->contours[contour] &&
5224 outline->tags[point] & FT_Curve_Tag_On) {
5225 /* add closing pt for bezier */
5226 if(buf)
5227 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5228 cpfx++;
5229 point++;
5231 if(buf) {
5232 ppc->wType = type;
5233 ppc->cpfx = cpfx;
5235 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5237 if(buf)
5238 pph->cb = needed - pph_start;
5240 break;
5242 case GGO_BEZIER:
5244 /* Convert the quadratic Beziers to cubic Beziers.
5245 The parametric eqn for a cubic Bezier is, from PLRM:
5246 r(t) = at^3 + bt^2 + ct + r0
5247 with the control points:
5248 r1 = r0 + c/3
5249 r2 = r1 + (c + b)/3
5250 r3 = r0 + c + b + a
5252 A quadratic Beizer has the form:
5253 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5255 So equating powers of t leads to:
5256 r1 = 2/3 p1 + 1/3 p0
5257 r2 = 2/3 p1 + 1/3 p2
5258 and of course r0 = p0, r3 = p2
5261 int contour, point = 0, first_pt;
5262 FT_Outline *outline = &ft_face->glyph->outline;
5263 TTPOLYGONHEADER *pph;
5264 TTPOLYCURVE *ppc;
5265 DWORD pph_start, cpfx, type;
5266 FT_Vector cubic_control[4];
5267 if(buflen == 0) buf = NULL;
5269 if (needsTransform && buf) {
5270 pFT_Outline_Transform(outline, &transMat);
5273 for(contour = 0; contour < outline->n_contours; contour++) {
5274 pph_start = needed;
5275 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5276 first_pt = point;
5277 if(buf) {
5278 pph->dwType = TT_POLYGON_TYPE;
5279 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5281 needed += sizeof(*pph);
5282 point++;
5283 while(point <= outline->contours[contour]) {
5284 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5285 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5286 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5287 cpfx = 0;
5288 do {
5289 if(type == TT_PRIM_LINE) {
5290 if(buf)
5291 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5292 cpfx++;
5293 point++;
5294 } else {
5295 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5296 so cpfx = 3n */
5298 /* FIXME: Possible optimization in endpoint calculation
5299 if there are two consecutive curves */
5300 cubic_control[0] = outline->points[point-1];
5301 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5302 cubic_control[0].x += outline->points[point].x + 1;
5303 cubic_control[0].y += outline->points[point].y + 1;
5304 cubic_control[0].x >>= 1;
5305 cubic_control[0].y >>= 1;
5307 if(point+1 > outline->contours[contour])
5308 cubic_control[3] = outline->points[first_pt];
5309 else {
5310 cubic_control[3] = outline->points[point+1];
5311 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5312 cubic_control[3].x += outline->points[point].x + 1;
5313 cubic_control[3].y += outline->points[point].y + 1;
5314 cubic_control[3].x >>= 1;
5315 cubic_control[3].y >>= 1;
5318 /* r1 = 1/3 p0 + 2/3 p1
5319 r2 = 1/3 p2 + 2/3 p1 */
5320 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5321 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5322 cubic_control[2] = cubic_control[1];
5323 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5324 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5325 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5326 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5327 if(buf) {
5328 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5329 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5330 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5332 cpfx += 3;
5333 point++;
5335 } while(point <= outline->contours[contour] &&
5336 (outline->tags[point] & FT_Curve_Tag_On) ==
5337 (outline->tags[point-1] & FT_Curve_Tag_On));
5338 /* At the end of a contour Windows adds the start point,
5339 but only for Beziers and we've already done that.
5341 if(point <= outline->contours[contour] &&
5342 outline->tags[point] & FT_Curve_Tag_On) {
5343 /* This is the closing pt of a bezier, but we've already
5344 added it, so just inc point and carry on */
5345 point++;
5347 if(buf) {
5348 ppc->wType = type;
5349 ppc->cpfx = cpfx;
5351 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5353 if(buf)
5354 pph->cb = needed - pph_start;
5356 break;
5359 default:
5360 FIXME("Unsupported format %d\n", format);
5361 LeaveCriticalSection( &freetype_cs );
5362 return GDI_ERROR;
5364 LeaveCriticalSection( &freetype_cs );
5365 return needed;
5368 static BOOL get_bitmap_text_metrics(GdiFont *font)
5370 FT_Face ft_face = font->ft_face;
5371 #ifdef HAVE_FREETYPE_FTWINFNT_H
5372 FT_WinFNT_HeaderRec winfnt_header;
5373 #endif
5374 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5375 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5376 font->potm->otmSize = size;
5378 #define TM font->potm->otmTextMetrics
5379 #ifdef HAVE_FREETYPE_FTWINFNT_H
5380 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5382 TM.tmHeight = winfnt_header.pixel_height;
5383 TM.tmAscent = winfnt_header.ascent;
5384 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5385 TM.tmInternalLeading = winfnt_header.internal_leading;
5386 TM.tmExternalLeading = winfnt_header.external_leading;
5387 TM.tmAveCharWidth = winfnt_header.avg_width;
5388 TM.tmMaxCharWidth = winfnt_header.max_width;
5389 TM.tmWeight = winfnt_header.weight;
5390 TM.tmOverhang = 0;
5391 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5392 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5393 TM.tmFirstChar = winfnt_header.first_char;
5394 TM.tmLastChar = winfnt_header.last_char;
5395 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5396 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5397 TM.tmItalic = winfnt_header.italic;
5398 TM.tmUnderlined = font->underline;
5399 TM.tmStruckOut = font->strikeout;
5400 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5401 TM.tmCharSet = winfnt_header.charset;
5403 else
5404 #endif
5406 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5407 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5408 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5409 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5410 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5411 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5412 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5413 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5414 TM.tmOverhang = 0;
5415 TM.tmDigitizedAspectX = 96; /* FIXME */
5416 TM.tmDigitizedAspectY = 96; /* FIXME */
5417 TM.tmFirstChar = 1;
5418 TM.tmLastChar = 255;
5419 TM.tmDefaultChar = 32;
5420 TM.tmBreakChar = 32;
5421 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5422 TM.tmUnderlined = font->underline;
5423 TM.tmStruckOut = font->strikeout;
5424 /* NB inverted meaning of TMPF_FIXED_PITCH */
5425 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5426 TM.tmCharSet = font->charset;
5428 #undef TM
5430 return TRUE;
5434 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5436 double scale_x, scale_y;
5438 if (font->aveWidth)
5440 scale_x = (double)font->aveWidth;
5441 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5443 else
5444 scale_x = font->scale_y;
5446 scale_x *= fabs(font->font_desc.matrix.eM11);
5447 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5449 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5450 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5452 SCALE_Y(ptm->tmHeight);
5453 SCALE_Y(ptm->tmAscent);
5454 SCALE_Y(ptm->tmDescent);
5455 SCALE_Y(ptm->tmInternalLeading);
5456 SCALE_Y(ptm->tmExternalLeading);
5457 SCALE_Y(ptm->tmOverhang);
5459 SCALE_X(ptm->tmAveCharWidth);
5460 SCALE_X(ptm->tmMaxCharWidth);
5462 #undef SCALE_X
5463 #undef SCALE_Y
5466 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5468 double scale_x, scale_y;
5470 if (font->aveWidth)
5472 scale_x = (double)font->aveWidth;
5473 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5475 else
5476 scale_x = font->scale_y;
5478 scale_x *= fabs(font->font_desc.matrix.eM11);
5479 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5481 scale_font_metrics(font, &potm->otmTextMetrics);
5483 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5484 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5486 SCALE_Y(potm->otmAscent);
5487 SCALE_Y(potm->otmDescent);
5488 SCALE_Y(potm->otmLineGap);
5489 SCALE_Y(potm->otmsCapEmHeight);
5490 SCALE_Y(potm->otmsXHeight);
5491 SCALE_Y(potm->otmrcFontBox.top);
5492 SCALE_Y(potm->otmrcFontBox.bottom);
5493 SCALE_X(potm->otmrcFontBox.left);
5494 SCALE_X(potm->otmrcFontBox.right);
5495 SCALE_Y(potm->otmMacAscent);
5496 SCALE_Y(potm->otmMacDescent);
5497 SCALE_Y(potm->otmMacLineGap);
5498 SCALE_X(potm->otmptSubscriptSize.x);
5499 SCALE_Y(potm->otmptSubscriptSize.y);
5500 SCALE_X(potm->otmptSubscriptOffset.x);
5501 SCALE_Y(potm->otmptSubscriptOffset.y);
5502 SCALE_X(potm->otmptSuperscriptSize.x);
5503 SCALE_Y(potm->otmptSuperscriptSize.y);
5504 SCALE_X(potm->otmptSuperscriptOffset.x);
5505 SCALE_Y(potm->otmptSuperscriptOffset.y);
5506 SCALE_Y(potm->otmsStrikeoutSize);
5507 SCALE_Y(potm->otmsStrikeoutPosition);
5508 SCALE_Y(potm->otmsUnderscoreSize);
5509 SCALE_Y(potm->otmsUnderscorePosition);
5511 #undef SCALE_X
5512 #undef SCALE_Y
5515 /*************************************************************
5516 * WineEngGetTextMetrics
5519 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5521 GDI_CheckNotLock();
5522 EnterCriticalSection( &freetype_cs );
5523 if(!font->potm) {
5524 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5525 if(!get_bitmap_text_metrics(font))
5527 LeaveCriticalSection( &freetype_cs );
5528 return FALSE;
5531 /* Make sure that the font has sane width/height ratio */
5532 if (font->aveWidth)
5534 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5536 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5537 font->aveWidth = 0;
5542 *ptm = font->potm->otmTextMetrics;
5543 scale_font_metrics(font, ptm);
5544 LeaveCriticalSection( &freetype_cs );
5545 return TRUE;
5548 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5550 int i;
5552 for(i = 0; i < ft_face->num_charmaps; i++)
5554 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5555 return TRUE;
5557 return FALSE;
5560 /*************************************************************
5561 * WineEngGetOutlineTextMetrics
5564 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5565 OUTLINETEXTMETRICW *potm)
5567 FT_Face ft_face = font->ft_face;
5568 UINT needed, lenfam, lensty, ret;
5569 TT_OS2 *pOS2;
5570 TT_HoriHeader *pHori;
5571 TT_Postscript *pPost;
5572 FT_Fixed x_scale, y_scale;
5573 WCHAR *family_nameW, *style_nameW;
5574 static const WCHAR spaceW[] = {' ', '\0'};
5575 char *cp;
5576 INT ascent, descent;
5578 TRACE("font=%p\n", font);
5580 if(!FT_IS_SCALABLE(ft_face))
5581 return 0;
5583 GDI_CheckNotLock();
5584 EnterCriticalSection( &freetype_cs );
5586 if(font->potm) {
5587 if(cbSize >= font->potm->otmSize)
5589 memcpy(potm, font->potm, font->potm->otmSize);
5590 scale_outline_font_metrics(font, potm);
5592 LeaveCriticalSection( &freetype_cs );
5593 return font->potm->otmSize;
5597 needed = sizeof(*potm);
5599 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5600 family_nameW = strdupW(font->name);
5602 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5603 * sizeof(WCHAR);
5604 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5605 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5606 style_nameW, lensty/sizeof(WCHAR));
5608 /* These names should be read from the TT name table */
5610 /* length of otmpFamilyName */
5611 needed += lenfam;
5613 /* length of otmpFaceName */
5614 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5615 needed += lenfam; /* just the family name */
5616 } else {
5617 needed += lenfam + lensty; /* family + " " + style */
5620 /* length of otmpStyleName */
5621 needed += lensty;
5623 /* length of otmpFullName */
5624 needed += lenfam + lensty;
5627 x_scale = ft_face->size->metrics.x_scale;
5628 y_scale = ft_face->size->metrics.y_scale;
5630 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5631 if(!pOS2) {
5632 FIXME("Can't find OS/2 table - not TT font?\n");
5633 ret = 0;
5634 goto end;
5637 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5638 if(!pHori) {
5639 FIXME("Can't find HHEA table - not TT font?\n");
5640 ret = 0;
5641 goto end;
5644 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5646 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",
5647 pOS2->usWinAscent, pOS2->usWinDescent,
5648 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5649 ft_face->ascender, ft_face->descender, ft_face->height,
5650 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5651 ft_face->bbox.yMax, ft_face->bbox.yMin);
5653 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5654 font->potm->otmSize = needed;
5656 #define TM font->potm->otmTextMetrics
5658 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5659 ascent = pHori->Ascender;
5660 descent = -pHori->Descender;
5661 } else {
5662 ascent = pOS2->usWinAscent;
5663 descent = pOS2->usWinDescent;
5666 if(font->yMax) {
5667 TM.tmAscent = font->yMax;
5668 TM.tmDescent = -font->yMin;
5669 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5670 } else {
5671 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5672 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5673 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5674 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5677 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5679 /* MSDN says:
5680 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5682 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5683 ((ascent + descent) -
5684 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5686 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5687 if (TM.tmAveCharWidth == 0) {
5688 TM.tmAveCharWidth = 1;
5690 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5691 TM.tmWeight = FW_REGULAR;
5692 if (font->fake_bold)
5693 TM.tmWeight = FW_BOLD;
5694 else
5696 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5698 if (pOS2->usWeightClass > FW_MEDIUM)
5699 TM.tmWeight = pOS2->usWeightClass;
5701 else if (pOS2->usWeightClass <= FW_MEDIUM)
5702 TM.tmWeight = pOS2->usWeightClass;
5704 TM.tmOverhang = 0;
5705 TM.tmDigitizedAspectX = 300;
5706 TM.tmDigitizedAspectY = 300;
5707 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5708 * symbol range to 0 - f0ff
5711 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5713 TM.tmFirstChar = 0;
5714 switch(GetACP())
5716 case 1257: /* Baltic */
5717 TM.tmLastChar = 0xf8fd;
5718 break;
5719 default:
5720 TM.tmLastChar = 0xf0ff;
5722 TM.tmBreakChar = 0x20;
5723 TM.tmDefaultChar = 0x1f;
5725 else
5727 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5728 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5730 if(pOS2->usFirstCharIndex <= 1)
5731 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5732 else if (pOS2->usFirstCharIndex > 0xff)
5733 TM.tmBreakChar = 0x20;
5734 else
5735 TM.tmBreakChar = pOS2->usFirstCharIndex;
5736 TM.tmDefaultChar = TM.tmBreakChar - 1;
5738 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5739 TM.tmUnderlined = font->underline;
5740 TM.tmStruckOut = font->strikeout;
5742 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5743 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5744 (pOS2->version == 0xFFFFU ||
5745 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5746 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5747 else
5748 TM.tmPitchAndFamily = 0;
5750 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5752 case PAN_FAMILY_SCRIPT:
5753 TM.tmPitchAndFamily |= FF_SCRIPT;
5754 break;
5756 case PAN_FAMILY_DECORATIVE:
5757 TM.tmPitchAndFamily |= FF_DECORATIVE;
5758 break;
5760 case PAN_ANY:
5761 case PAN_NO_FIT:
5762 case PAN_FAMILY_TEXT_DISPLAY:
5763 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5764 /* which is clearly not what the panose spec says. */
5765 default:
5766 if(TM.tmPitchAndFamily == 0 || /* fixed */
5767 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5768 TM.tmPitchAndFamily = FF_MODERN;
5769 else
5771 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5773 case PAN_ANY:
5774 case PAN_NO_FIT:
5775 default:
5776 TM.tmPitchAndFamily |= FF_DONTCARE;
5777 break;
5779 case PAN_SERIF_COVE:
5780 case PAN_SERIF_OBTUSE_COVE:
5781 case PAN_SERIF_SQUARE_COVE:
5782 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5783 case PAN_SERIF_SQUARE:
5784 case PAN_SERIF_THIN:
5785 case PAN_SERIF_BONE:
5786 case PAN_SERIF_EXAGGERATED:
5787 case PAN_SERIF_TRIANGLE:
5788 TM.tmPitchAndFamily |= FF_ROMAN;
5789 break;
5791 case PAN_SERIF_NORMAL_SANS:
5792 case PAN_SERIF_OBTUSE_SANS:
5793 case PAN_SERIF_PERP_SANS:
5794 case PAN_SERIF_FLARED:
5795 case PAN_SERIF_ROUNDED:
5796 TM.tmPitchAndFamily |= FF_SWISS;
5797 break;
5800 break;
5803 if(FT_IS_SCALABLE(ft_face))
5804 TM.tmPitchAndFamily |= TMPF_VECTOR;
5806 if(FT_IS_SFNT(ft_face))
5808 if (font->ntmFlags & NTM_PS_OPENTYPE)
5809 TM.tmPitchAndFamily |= TMPF_DEVICE;
5810 else
5811 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5814 TM.tmCharSet = font->charset;
5816 font->potm->otmFiller = 0;
5817 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5818 font->potm->otmfsSelection = pOS2->fsSelection;
5819 font->potm->otmfsType = pOS2->fsType;
5820 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5821 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5822 font->potm->otmItalicAngle = 0; /* POST table */
5823 font->potm->otmEMSquare = ft_face->units_per_EM;
5824 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5825 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5826 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5827 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5828 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5829 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5830 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5831 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5832 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5833 font->potm->otmMacAscent = TM.tmAscent;
5834 font->potm->otmMacDescent = -TM.tmDescent;
5835 font->potm->otmMacLineGap = font->potm->otmLineGap;
5836 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5837 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5838 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5839 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5840 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5841 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5842 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5843 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5844 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5845 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5846 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5847 if(!pPost) {
5848 font->potm->otmsUnderscoreSize = 0;
5849 font->potm->otmsUnderscorePosition = 0;
5850 } else {
5851 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5852 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5854 #undef TM
5856 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5857 cp = (char*)font->potm + sizeof(*font->potm);
5858 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5859 strcpyW((WCHAR*)cp, family_nameW);
5860 cp += lenfam;
5861 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5862 strcpyW((WCHAR*)cp, style_nameW);
5863 cp += lensty;
5864 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5865 strcpyW((WCHAR*)cp, family_nameW);
5866 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5867 strcatW((WCHAR*)cp, spaceW);
5868 strcatW((WCHAR*)cp, style_nameW);
5869 cp += lenfam + lensty;
5870 } else
5871 cp += lenfam;
5872 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5873 strcpyW((WCHAR*)cp, family_nameW);
5874 strcatW((WCHAR*)cp, spaceW);
5875 strcatW((WCHAR*)cp, style_nameW);
5876 ret = needed;
5878 if(potm && needed <= cbSize)
5880 memcpy(potm, font->potm, font->potm->otmSize);
5881 scale_outline_font_metrics(font, potm);
5884 end:
5885 HeapFree(GetProcessHeap(), 0, style_nameW);
5886 HeapFree(GetProcessHeap(), 0, family_nameW);
5888 LeaveCriticalSection( &freetype_cs );
5889 return ret;
5892 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5894 HFONTLIST *hfontlist;
5895 child->font = alloc_font();
5896 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5897 if(!child->font->ft_face)
5899 free_font(child->font);
5900 child->font = NULL;
5901 return FALSE;
5904 child->font->font_desc = font->font_desc;
5905 child->font->ntmFlags = child->face->ntmFlags;
5906 child->font->orientation = font->orientation;
5907 child->font->scale_y = font->scale_y;
5908 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5909 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5910 child->font->name = strdupW(child->face->family->FamilyName);
5911 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5912 child->font->base_font = font;
5913 list_add_head(&child_font_list, &child->font->entry);
5914 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5915 return TRUE;
5918 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5920 FT_UInt g;
5921 CHILD_FONT *child_font;
5923 if(font->base_font)
5924 font = font->base_font;
5926 *linked_font = font;
5928 if((*glyph = get_glyph_index(font, c)))
5929 return TRUE;
5931 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5933 if(!child_font->font)
5934 if(!load_child_font(font, child_font))
5935 continue;
5937 if(!child_font->font->ft_face)
5938 continue;
5939 g = get_glyph_index(child_font->font, c);
5940 if(g)
5942 *glyph = g;
5943 *linked_font = child_font->font;
5944 return TRUE;
5947 return FALSE;
5950 /*************************************************************
5951 * WineEngGetCharWidth
5954 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5955 LPINT 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 GDI_CheckNotLock();
5966 EnterCriticalSection( &freetype_cs );
5967 for(c = firstChar; c <= lastChar; c++) {
5968 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5969 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5970 &gm, 0, NULL, &identity);
5971 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5973 LeaveCriticalSection( &freetype_cs );
5974 return TRUE;
5977 /*************************************************************
5978 * WineEngGetCharABCWidths
5981 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5982 LPABC buffer)
5984 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5985 UINT c;
5986 GLYPHMETRICS gm;
5987 FT_UInt glyph_index;
5988 GdiFont *linked_font;
5990 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5992 if(!FT_IS_SCALABLE(font->ft_face))
5993 return FALSE;
5995 GDI_CheckNotLock();
5996 EnterCriticalSection( &freetype_cs );
5998 for(c = firstChar; c <= lastChar; c++) {
5999 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6000 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6001 &gm, 0, NULL, &identity);
6002 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6003 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6004 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6005 FONT_GM(linked_font,glyph_index)->bbx;
6007 LeaveCriticalSection( &freetype_cs );
6008 return TRUE;
6011 /*************************************************************
6012 * WineEngGetCharABCWidthsFloat
6015 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6017 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6018 UINT c;
6019 GLYPHMETRICS gm;
6020 FT_UInt glyph_index;
6021 GdiFont *linked_font;
6023 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6025 GDI_CheckNotLock();
6026 EnterCriticalSection( &freetype_cs );
6028 for (c = first; c <= last; c++)
6030 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6031 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6032 &gm, 0, NULL, &identity);
6033 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6034 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6035 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6036 FONT_GM(linked_font, glyph_index)->lsb -
6037 FONT_GM(linked_font, glyph_index)->bbx;
6039 LeaveCriticalSection( &freetype_cs );
6040 return TRUE;
6043 /*************************************************************
6044 * WineEngGetCharABCWidthsI
6047 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6048 LPABC buffer)
6050 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6051 UINT c;
6052 GLYPHMETRICS gm;
6053 FT_UInt glyph_index;
6054 GdiFont *linked_font;
6056 if(!FT_HAS_HORIZONTAL(font->ft_face))
6057 return FALSE;
6059 GDI_CheckNotLock();
6060 EnterCriticalSection( &freetype_cs );
6062 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6063 if (!pgi)
6064 for(c = firstChar; c < firstChar+count; c++) {
6065 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6066 &gm, 0, NULL, &identity);
6067 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6068 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6069 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6070 - FONT_GM(linked_font,c)->bbx;
6072 else
6073 for(c = 0; c < count; c++) {
6074 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6075 &gm, 0, NULL, &identity);
6076 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6077 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6078 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6079 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6082 LeaveCriticalSection( &freetype_cs );
6083 return TRUE;
6086 /*************************************************************
6087 * WineEngGetTextExtentExPoint
6090 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6091 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6093 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6094 INT idx;
6095 INT nfit = 0, ext;
6096 GLYPHMETRICS gm;
6097 TEXTMETRICW tm;
6098 FT_UInt glyph_index;
6099 GdiFont *linked_font;
6101 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6102 max_ext, size);
6104 GDI_CheckNotLock();
6105 EnterCriticalSection( &freetype_cs );
6107 size->cx = 0;
6108 WineEngGetTextMetrics(font, &tm);
6109 size->cy = tm.tmHeight;
6111 for(idx = 0; idx < count; idx++) {
6112 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6113 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6114 &gm, 0, NULL, &identity);
6115 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6116 ext = size->cx;
6117 if (! pnfit || ext <= max_ext) {
6118 ++nfit;
6119 if (dxs)
6120 dxs[idx] = ext;
6124 if (pnfit)
6125 *pnfit = nfit;
6127 LeaveCriticalSection( &freetype_cs );
6128 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6129 return TRUE;
6132 /*************************************************************
6133 * WineEngGetTextExtentExPointI
6136 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6137 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6139 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6140 INT idx;
6141 INT nfit = 0, ext;
6142 GLYPHMETRICS gm;
6143 TEXTMETRICW tm;
6145 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6147 GDI_CheckNotLock();
6148 EnterCriticalSection( &freetype_cs );
6150 size->cx = 0;
6151 WineEngGetTextMetrics(font, &tm);
6152 size->cy = tm.tmHeight;
6154 for(idx = 0; idx < count; idx++) {
6155 WineEngGetGlyphOutline(font, indices[idx],
6156 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6157 &identity);
6158 size->cx += FONT_GM(font,indices[idx])->adv;
6159 ext = size->cx;
6160 if (! pnfit || ext <= max_ext) {
6161 ++nfit;
6162 if (dxs)
6163 dxs[idx] = ext;
6167 if (pnfit)
6168 *pnfit = nfit;
6170 LeaveCriticalSection( &freetype_cs );
6171 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6172 return TRUE;
6175 /*************************************************************
6176 * WineEngGetFontData
6179 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6180 DWORD cbData)
6182 FT_Face ft_face = font->ft_face;
6183 FT_ULong len;
6184 FT_Error err;
6186 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6187 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6188 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6190 if(!FT_IS_SFNT(ft_face))
6191 return GDI_ERROR;
6193 if(!buf || !cbData)
6194 len = 0;
6195 else
6196 len = cbData;
6198 if(table) { /* MS tags differ in endianness from FT ones */
6199 table = table >> 24 | table << 24 |
6200 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6203 /* make sure value of len is the value freetype says it needs */
6204 if(buf && len)
6206 FT_ULong needed = 0;
6207 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6208 if( !err && needed < len) len = needed;
6210 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6212 if(err) {
6213 TRACE("Can't find table %c%c%c%c\n",
6214 /* bytes were reversed */
6215 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6216 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6217 return GDI_ERROR;
6219 return len;
6222 /*************************************************************
6223 * WineEngGetTextFace
6226 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6228 INT n = strlenW(font->name) + 1;
6229 if(str) {
6230 lstrcpynW(str, font->name, count);
6231 return min(count, n);
6232 } else
6233 return n;
6236 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6238 if (fs) *fs = font->fs;
6239 return font->charset;
6242 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6244 GdiFont *font = dc->gdiFont, *linked_font;
6245 struct list *first_hfont;
6246 BOOL ret;
6248 GDI_CheckNotLock();
6249 EnterCriticalSection( &freetype_cs );
6250 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6251 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6252 if(font == linked_font)
6253 *new_hfont = dc->hFont;
6254 else
6256 first_hfont = list_head(&linked_font->hfontlist);
6257 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6259 LeaveCriticalSection( &freetype_cs );
6260 return ret;
6263 /* Retrieve a list of supported Unicode ranges for a given font.
6264 * Can be called with NULL gs to calculate the buffer size. Returns
6265 * the number of ranges found.
6267 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6269 DWORD num_ranges = 0;
6271 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6273 FT_UInt glyph_code;
6274 FT_ULong char_code, char_code_prev;
6276 glyph_code = 0;
6277 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6279 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6280 face->num_glyphs, glyph_code, char_code);
6282 if (!glyph_code) return 0;
6284 if (gs)
6286 gs->ranges[0].wcLow = (USHORT)char_code;
6287 gs->ranges[0].cGlyphs = 0;
6288 gs->cGlyphsSupported = 0;
6291 num_ranges = 1;
6292 while (glyph_code)
6294 if (char_code < char_code_prev)
6296 ERR("expected increasing char code from FT_Get_Next_Char\n");
6297 return 0;
6299 if (char_code - char_code_prev > 1)
6301 num_ranges++;
6302 if (gs)
6304 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6305 gs->ranges[num_ranges - 1].cGlyphs = 1;
6306 gs->cGlyphsSupported++;
6309 else if (gs)
6311 gs->ranges[num_ranges - 1].cGlyphs++;
6312 gs->cGlyphsSupported++;
6314 char_code_prev = char_code;
6315 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6318 else
6319 FIXME("encoding %u not supported\n", face->charmap->encoding);
6321 return num_ranges;
6324 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6326 DWORD size = 0;
6327 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6329 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6330 if (glyphset)
6332 glyphset->cbThis = size;
6333 glyphset->cRanges = num_ranges;
6334 glyphset->flAccel = 0;
6336 return size;
6339 /*************************************************************
6340 * FontIsLinked
6342 BOOL WineEngFontIsLinked(GdiFont *font)
6344 BOOL ret;
6345 GDI_CheckNotLock();
6346 EnterCriticalSection( &freetype_cs );
6347 ret = !list_empty(&font->child_fonts);
6348 LeaveCriticalSection( &freetype_cs );
6349 return ret;
6352 static BOOL is_hinting_enabled(void)
6354 /* Use the >= 2.2.0 function if available */
6355 if(pFT_Get_TrueType_Engine_Type)
6357 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6358 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6360 #ifdef FT_DRIVER_HAS_HINTER
6361 else
6363 FT_Module mod;
6365 /* otherwise if we've been compiled with < 2.2.0 headers
6366 use the internal macro */
6367 mod = pFT_Get_Module(library, "truetype");
6368 if(mod && FT_DRIVER_HAS_HINTER(mod))
6369 return TRUE;
6371 #endif
6373 return FALSE;
6376 static BOOL is_subpixel_rendering_enabled( void )
6378 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6379 return pFT_Library_SetLcdFilter &&
6380 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6381 #else
6382 return FALSE;
6383 #endif
6386 /*************************************************************************
6387 * GetRasterizerCaps (GDI32.@)
6389 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6391 static int hinting = -1;
6392 static int subpixel = -1;
6394 if(hinting == -1)
6396 hinting = is_hinting_enabled();
6397 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6400 if ( subpixel == -1 )
6402 subpixel = is_subpixel_rendering_enabled();
6403 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6406 lprs->nSize = sizeof(RASTERIZER_STATUS);
6407 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6408 if ( subpixel )
6409 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6410 lprs->nLanguageID = 0;
6411 return TRUE;
6414 /*************************************************************
6415 * WineEngRealizationInfo
6417 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6419 FIXME("(%p, %p): stub!\n", font, info);
6421 info->flags = 1;
6422 if(FT_IS_SCALABLE(font->ft_face))
6423 info->flags |= 2;
6425 info->cache_num = font->cache_num;
6426 info->unknown2 = -1;
6427 return TRUE;
6430 /*************************************************************************
6431 * Kerning support for TrueType fonts
6433 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6435 struct TT_kern_table
6437 USHORT version;
6438 USHORT nTables;
6441 struct TT_kern_subtable
6443 USHORT version;
6444 USHORT length;
6445 union
6447 USHORT word;
6448 struct
6450 USHORT horizontal : 1;
6451 USHORT minimum : 1;
6452 USHORT cross_stream: 1;
6453 USHORT override : 1;
6454 USHORT reserved1 : 4;
6455 USHORT format : 8;
6456 } bits;
6457 } coverage;
6460 struct TT_format0_kern_subtable
6462 USHORT nPairs;
6463 USHORT searchRange;
6464 USHORT entrySelector;
6465 USHORT rangeShift;
6468 struct TT_kern_pair
6470 USHORT left;
6471 USHORT right;
6472 short value;
6475 static DWORD parse_format0_kern_subtable(GdiFont *font,
6476 const struct TT_format0_kern_subtable *tt_f0_ks,
6477 const USHORT *glyph_to_char,
6478 KERNINGPAIR *kern_pair, DWORD cPairs)
6480 USHORT i, nPairs;
6481 const struct TT_kern_pair *tt_kern_pair;
6483 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6485 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6487 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6488 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6489 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6491 if (!kern_pair || !cPairs)
6492 return nPairs;
6494 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6496 nPairs = min(nPairs, cPairs);
6498 for (i = 0; i < nPairs; i++)
6500 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6501 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6502 /* this algorithm appears to better match what Windows does */
6503 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6504 if (kern_pair->iKernAmount < 0)
6506 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6507 kern_pair->iKernAmount -= font->ppem;
6509 else if (kern_pair->iKernAmount > 0)
6511 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6512 kern_pair->iKernAmount += font->ppem;
6514 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6516 TRACE("left %u right %u value %d\n",
6517 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6519 kern_pair++;
6521 TRACE("copied %u entries\n", nPairs);
6522 return nPairs;
6525 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6527 DWORD length;
6528 void *buf;
6529 const struct TT_kern_table *tt_kern_table;
6530 const struct TT_kern_subtable *tt_kern_subtable;
6531 USHORT i, nTables;
6532 USHORT *glyph_to_char;
6534 GDI_CheckNotLock();
6535 EnterCriticalSection( &freetype_cs );
6536 if (font->total_kern_pairs != (DWORD)-1)
6538 if (cPairs && kern_pair)
6540 cPairs = min(cPairs, font->total_kern_pairs);
6541 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6542 LeaveCriticalSection( &freetype_cs );
6543 return cPairs;
6545 LeaveCriticalSection( &freetype_cs );
6546 return font->total_kern_pairs;
6549 font->total_kern_pairs = 0;
6551 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6553 if (length == GDI_ERROR)
6555 TRACE("no kerning data in the font\n");
6556 LeaveCriticalSection( &freetype_cs );
6557 return 0;
6560 buf = HeapAlloc(GetProcessHeap(), 0, length);
6561 if (!buf)
6563 WARN("Out of memory\n");
6564 LeaveCriticalSection( &freetype_cs );
6565 return 0;
6568 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6570 /* build a glyph index to char code map */
6571 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6572 if (!glyph_to_char)
6574 WARN("Out of memory allocating a glyph index to char code map\n");
6575 HeapFree(GetProcessHeap(), 0, buf);
6576 LeaveCriticalSection( &freetype_cs );
6577 return 0;
6580 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6582 FT_UInt glyph_code;
6583 FT_ULong char_code;
6585 glyph_code = 0;
6586 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6588 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6589 font->ft_face->num_glyphs, glyph_code, char_code);
6591 while (glyph_code)
6593 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6595 /* FIXME: This doesn't match what Windows does: it does some fancy
6596 * things with duplicate glyph index to char code mappings, while
6597 * we just avoid overriding existing entries.
6599 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6600 glyph_to_char[glyph_code] = (USHORT)char_code;
6602 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6605 else
6607 ULONG n;
6609 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6610 for (n = 0; n <= 65535; n++)
6611 glyph_to_char[n] = (USHORT)n;
6614 tt_kern_table = buf;
6615 nTables = GET_BE_WORD(tt_kern_table->nTables);
6616 TRACE("version %u, nTables %u\n",
6617 GET_BE_WORD(tt_kern_table->version), nTables);
6619 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6621 for (i = 0; i < nTables; i++)
6623 struct TT_kern_subtable tt_kern_subtable_copy;
6625 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6626 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6627 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6629 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6630 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6631 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6633 /* According to the TrueType specification this is the only format
6634 * that will be properly interpreted by Windows and OS/2
6636 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6638 DWORD new_chunk, old_total = font->total_kern_pairs;
6640 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6641 glyph_to_char, NULL, 0);
6642 font->total_kern_pairs += new_chunk;
6644 if (!font->kern_pairs)
6645 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6646 font->total_kern_pairs * sizeof(*font->kern_pairs));
6647 else
6648 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6649 font->total_kern_pairs * sizeof(*font->kern_pairs));
6651 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6652 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6654 else
6655 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6657 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6660 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6661 HeapFree(GetProcessHeap(), 0, buf);
6663 if (cPairs && kern_pair)
6665 cPairs = min(cPairs, font->total_kern_pairs);
6666 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6667 LeaveCriticalSection( &freetype_cs );
6668 return cPairs;
6670 LeaveCriticalSection( &freetype_cs );
6671 return font->total_kern_pairs;
6674 #else /* HAVE_FREETYPE */
6676 /*************************************************************************/
6678 BOOL WineEngInit(void)
6680 return FALSE;
6682 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6684 return NULL;
6686 BOOL WineEngDestroyFontInstance(HFONT hfont)
6688 return FALSE;
6691 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6693 return 1;
6696 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6697 LPWORD pgi, DWORD flags)
6699 return GDI_ERROR;
6702 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6703 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6704 const MAT2* lpmat)
6706 ERR("called but we don't have FreeType\n");
6707 return GDI_ERROR;
6710 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6712 ERR("called but we don't have FreeType\n");
6713 return FALSE;
6716 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6717 OUTLINETEXTMETRICW *potm)
6719 ERR("called but we don't have FreeType\n");
6720 return 0;
6723 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6724 LPINT buffer)
6726 ERR("called but we don't have FreeType\n");
6727 return FALSE;
6730 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6731 LPABC buffer)
6733 ERR("called but we don't have FreeType\n");
6734 return FALSE;
6737 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6739 ERR("called but we don't have FreeType\n");
6740 return FALSE;
6743 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6744 LPABC buffer)
6746 ERR("called but we don't have FreeType\n");
6747 return FALSE;
6750 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6751 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6753 ERR("called but we don't have FreeType\n");
6754 return FALSE;
6757 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6758 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6760 ERR("called but we don't have FreeType\n");
6761 return FALSE;
6764 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6765 DWORD cbData)
6767 ERR("called but we don't have FreeType\n");
6768 return GDI_ERROR;
6771 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6773 ERR("called but we don't have FreeType\n");
6774 return 0;
6777 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6779 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6780 return 1;
6783 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6785 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6786 return TRUE;
6789 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6791 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6792 return NULL;
6795 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6797 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6798 return DEFAULT_CHARSET;
6801 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6803 return FALSE;
6806 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6808 FIXME("(%p, %p): stub\n", font, glyphset);
6809 return 0;
6812 BOOL WineEngFontIsLinked(GdiFont *font)
6814 return FALSE;
6817 /*************************************************************************
6818 * GetRasterizerCaps (GDI32.@)
6820 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6822 lprs->nSize = sizeof(RASTERIZER_STATUS);
6823 lprs->wFlags = 0;
6824 lprs->nLanguageID = 0;
6825 return TRUE;
6828 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6830 ERR("called but we don't have FreeType\n");
6831 return 0;
6834 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6836 ERR("called but we don't have FreeType\n");
6837 return FALSE;
6840 #endif /* HAVE_FREETYPE */