gdi32: Make AddFontToList skip adding a face into global lists if the font is not...
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobc35e3327eb457ed54ccf65d13f845e0fe2dd2d69
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
94 #ifdef HAVE_FREETYPE
96 #ifdef HAVE_FT2BUILD_H
97 #include <ft2build.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
101 #endif
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
104 #endif
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
110 #endif
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
113 #endif
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
116 #endif
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
119 #endif
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
122 #endif
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
134 #endif
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 typedef enum
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
143 #endif
145 static FT_Library library = 0;
146 typedef struct
148 FT_Int major;
149 FT_Int minor;
150 FT_Int patch;
151 } FT_Version_t;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
170 #else
171 MAKE_FUNCPTR(FT_MulFix);
172 #endif
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
193 #endif
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
208 #endif
210 #undef MAKE_FUNCPTR
212 #ifndef FT_MAKE_TAG
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #endif
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
220 #endif
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
223 #endif
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
226 #endif
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #endif
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
233 #else
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 #endif
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
238 typedef struct {
239 FT_Short height;
240 FT_Short width;
241 FT_Pos size;
242 FT_Pos x_ppem;
243 FT_Pos y_ppem;
244 FT_Short internal_leading;
245 } Bitmap_Size;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
250 typedef struct {
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
253 } My_FT_Bitmap_Size;
255 struct enum_data
257 ENUMLOGFONTEXW elf;
258 NEWTEXTMETRICEXW ntm;
259 DWORD type;
262 typedef struct tagFace {
263 struct list entry;
264 WCHAR *StyleName;
265 char *file;
266 void *font_data_ptr;
267 DWORD font_data_size;
268 FT_Long face_index;
269 FONTSIGNATURE fs;
270 FONTSIGNATURE fs_links;
271 DWORD ntmFlags;
272 FT_Fixed font_version;
273 BOOL scalable;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
279 } Face;
281 typedef struct tagFamily {
282 struct list entry;
283 const WCHAR *FamilyName;
284 struct list faces;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 struct list links;
355 } SYSTEM_LINKS;
357 #define GM_BLOCK_SIZE 128
358 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
360 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
361 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
362 #define UNUSED_CACHE_SIZE 10
363 static struct list child_font_list = LIST_INIT(child_font_list);
364 static struct list system_links = LIST_INIT(system_links);
366 static struct list font_subst_list = LIST_INIT(font_subst_list);
368 static struct list font_list = LIST_INIT(font_list);
370 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
371 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
372 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
374 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
375 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
376 'W','i','n','d','o','w','s','\\',
377 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
378 'F','o','n','t','s','\0'};
380 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
381 'W','i','n','d','o','w','s',' ','N','T','\\',
382 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
383 'F','o','n','t','s','\0'};
385 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
386 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
387 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
388 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
390 static const WCHAR * const SystemFontValues[4] = {
391 System_Value,
392 OEMFont_Value,
393 FixedSys_Value,
394 NULL
397 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
398 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
400 /* Interesting and well-known (frequently-assumed!) font names */
401 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
402 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 };
403 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
404 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
405 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
406 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
407 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
408 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
410 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
411 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
412 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
413 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
414 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
415 'E','u','r','o','p','e','a','n','\0'};
416 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
417 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
418 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
419 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
420 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
421 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
422 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
423 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
424 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
425 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
426 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
427 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
429 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
430 WesternW, /*00*/
431 Central_EuropeanW,
432 CyrillicW,
433 GreekW,
434 TurkishW,
435 HebrewW,
436 ArabicW,
437 BalticW,
438 VietnameseW, /*08*/
439 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
440 ThaiW,
441 JapaneseW,
442 CHINESE_GB2312W,
443 HangulW,
444 CHINESE_BIG5W,
445 Hangul_Johab_W,
446 NULL, NULL, /*23*/
447 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
448 SymbolW /*31*/
451 typedef struct {
452 WCHAR *name;
453 INT charset;
454 } NameCs;
456 typedef struct tagFontSubst {
457 struct list entry;
458 NameCs from;
459 NameCs to;
460 } FontSubst;
462 struct font_mapping
464 struct list entry;
465 int refcount;
466 dev_t dev;
467 ino_t ino;
468 void *data;
469 size_t size;
472 static struct list mappings_list = LIST_INIT( mappings_list );
474 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
476 static CRITICAL_SECTION freetype_cs;
477 static CRITICAL_SECTION_DEBUG critsect_debug =
479 0, 0, &freetype_cs,
480 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
481 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
483 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
485 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
487 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
488 static BOOL use_default_fallback = FALSE;
490 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
492 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
493 'W','i','n','d','o','w','s',' ','N','T','\\',
494 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
495 'S','y','s','t','e','m','L','i','n','k',0};
497 /****************************************
498 * Notes on .fon files
500 * The fonts System, FixedSys and Terminal are special. There are typically multiple
501 * versions installed for different resolutions and codepages. Windows stores which one to use
502 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
503 * Key Meaning
504 * FIXEDFON.FON FixedSys
505 * FONTS.FON System
506 * OEMFONT.FON Terminal
507 * LogPixels Current dpi set by the display control panel applet
508 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
509 * also has a LogPixels value that appears to mirror this)
511 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
512 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
513 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
514 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
515 * so that makes sense.
517 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
518 * to be mapped into the registry on Windows 2000 at least).
519 * I have
520 * woafont=app850.fon
521 * ega80woa.fon=ega80850.fon
522 * ega40woa.fon=ega40850.fon
523 * cga80woa.fon=cga80850.fon
524 * cga40woa.fon=cga40850.fon
527 /* These are all structures needed for the GSUB table */
529 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
530 #define TATEGAKI_LOWER_BOUND 0x02F1
532 typedef struct {
533 DWORD version;
534 WORD ScriptList;
535 WORD FeatureList;
536 WORD LookupList;
537 } GSUB_Header;
539 typedef struct {
540 CHAR ScriptTag[4];
541 WORD Script;
542 } GSUB_ScriptRecord;
544 typedef struct {
545 WORD ScriptCount;
546 GSUB_ScriptRecord ScriptRecord[1];
547 } GSUB_ScriptList;
549 typedef struct {
550 CHAR LangSysTag[4];
551 WORD LangSys;
552 } GSUB_LangSysRecord;
554 typedef struct {
555 WORD DefaultLangSys;
556 WORD LangSysCount;
557 GSUB_LangSysRecord LangSysRecord[1];
558 } GSUB_Script;
560 typedef struct {
561 WORD LookupOrder; /* Reserved */
562 WORD ReqFeatureIndex;
563 WORD FeatureCount;
564 WORD FeatureIndex[1];
565 } GSUB_LangSys;
567 typedef struct {
568 CHAR FeatureTag[4];
569 WORD Feature;
570 } GSUB_FeatureRecord;
572 typedef struct {
573 WORD FeatureCount;
574 GSUB_FeatureRecord FeatureRecord[1];
575 } GSUB_FeatureList;
577 typedef struct {
578 WORD FeatureParams; /* Reserved */
579 WORD LookupCount;
580 WORD LookupListIndex[1];
581 } GSUB_Feature;
583 typedef struct {
584 WORD LookupCount;
585 WORD Lookup[1];
586 } GSUB_LookupList;
588 typedef struct {
589 WORD LookupType;
590 WORD LookupFlag;
591 WORD SubTableCount;
592 WORD SubTable[1];
593 } GSUB_LookupTable;
595 typedef struct {
596 WORD CoverageFormat;
597 WORD GlyphCount;
598 WORD GlyphArray[1];
599 } GSUB_CoverageFormat1;
601 typedef struct {
602 WORD Start;
603 WORD End;
604 WORD StartCoverageIndex;
605 } GSUB_RangeRecord;
607 typedef struct {
608 WORD CoverageFormat;
609 WORD RangeCount;
610 GSUB_RangeRecord RangeRecord[1];
611 } GSUB_CoverageFormat2;
613 typedef struct {
614 WORD SubstFormat; /* = 1 */
615 WORD Coverage;
616 WORD DeltaGlyphID;
617 } GSUB_SingleSubstFormat1;
619 typedef struct {
620 WORD SubstFormat; /* = 2 */
621 WORD Coverage;
622 WORD GlyphCount;
623 WORD Substitute[1];
624 }GSUB_SingleSubstFormat2;
626 #ifdef HAVE_CARBON_CARBON_H
627 static char *find_cache_dir(void)
629 FSRef ref;
630 OSErr err;
631 static char cached_path[MAX_PATH];
632 static const char *wine = "/Wine", *fonts = "/Fonts";
634 if(*cached_path) return cached_path;
636 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
637 if(err != noErr)
639 WARN("can't create cached data folder\n");
640 return NULL;
642 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
643 if(err != noErr)
645 WARN("can't create cached data path\n");
646 *cached_path = '\0';
647 return NULL;
649 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
651 ERR("Could not create full path\n");
652 *cached_path = '\0';
653 return NULL;
655 strcat(cached_path, wine);
657 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
659 WARN("Couldn't mkdir %s\n", cached_path);
660 *cached_path = '\0';
661 return NULL;
663 strcat(cached_path, fonts);
664 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
666 WARN("Couldn't mkdir %s\n", cached_path);
667 *cached_path = '\0';
668 return NULL;
670 return cached_path;
673 /******************************************************************
674 * expand_mac_font
676 * Extracts individual TrueType font files from a Mac suitcase font
677 * and saves them into the user's caches directory (see
678 * find_cache_dir()).
679 * Returns a NULL terminated array of filenames.
681 * We do this because they are apps that try to read ttf files
682 * themselves and they don't like Mac suitcase files.
684 static char **expand_mac_font(const char *path)
686 FSRef ref;
687 SInt16 res_ref;
688 OSStatus s;
689 unsigned int idx;
690 const char *out_dir;
691 const char *filename;
692 int output_len;
693 struct {
694 char **array;
695 unsigned int size, max_size;
696 } ret;
698 TRACE("path %s\n", path);
700 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
701 if(s != noErr)
703 WARN("failed to get ref\n");
704 return NULL;
707 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
708 if(s != noErr)
710 TRACE("no data fork, so trying resource fork\n");
711 res_ref = FSOpenResFile(&ref, fsRdPerm);
712 if(res_ref == -1)
714 TRACE("unable to open resource fork\n");
715 return NULL;
719 ret.size = 0;
720 ret.max_size = 10;
721 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
722 if(!ret.array)
724 CloseResFile(res_ref);
725 return NULL;
728 out_dir = find_cache_dir();
730 filename = strrchr(path, '/');
731 if(!filename) filename = path;
732 else filename++;
734 /* output filename has the form out_dir/filename_%04x.ttf */
735 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
737 UseResFile(res_ref);
738 idx = 1;
739 while(1)
741 FamRec *fam_rec;
742 unsigned short *num_faces_ptr, num_faces, face;
743 AsscEntry *assoc;
744 Handle fond;
745 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
747 fond = Get1IndResource(fond_res, idx);
748 if(!fond) break;
749 TRACE("got fond resource %d\n", idx);
750 HLock(fond);
752 fam_rec = *(FamRec**)fond;
753 num_faces_ptr = (unsigned short *)(fam_rec + 1);
754 num_faces = GET_BE_WORD(*num_faces_ptr);
755 num_faces++;
756 assoc = (AsscEntry*)(num_faces_ptr + 1);
757 TRACE("num faces %04x\n", num_faces);
758 for(face = 0; face < num_faces; face++, assoc++)
760 Handle sfnt;
761 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
762 unsigned short size, font_id;
763 char *output;
765 size = GET_BE_WORD(assoc->fontSize);
766 font_id = GET_BE_WORD(assoc->fontID);
767 if(size != 0)
769 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
770 continue;
773 TRACE("trying to load sfnt id %04x\n", font_id);
774 sfnt = GetResource(sfnt_res, font_id);
775 if(!sfnt)
777 TRACE("can't get sfnt resource %04x\n", font_id);
778 continue;
781 output = HeapAlloc(GetProcessHeap(), 0, output_len);
782 if(output)
784 int fd;
786 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
788 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
789 if(fd != -1 || errno == EEXIST)
791 if(fd != -1)
793 unsigned char *sfnt_data;
795 HLock(sfnt);
796 sfnt_data = *(unsigned char**)sfnt;
797 write(fd, sfnt_data, GetHandleSize(sfnt));
798 HUnlock(sfnt);
799 close(fd);
801 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
803 ret.max_size *= 2;
804 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
806 ret.array[ret.size++] = output;
808 else
810 WARN("unable to create %s\n", output);
811 HeapFree(GetProcessHeap(), 0, output);
814 ReleaseResource(sfnt);
816 HUnlock(fond);
817 ReleaseResource(fond);
818 idx++;
820 CloseResFile(res_ref);
822 return ret.array;
825 #endif /* HAVE_CARBON_CARBON_H */
827 static inline BOOL is_win9x(void)
829 return GetVersion() & 0x80000000;
832 This function builds an FT_Fixed from a double. It fails if the absolute
833 value of the float number is greater than 32768.
835 static inline FT_Fixed FT_FixedFromFloat(double f)
837 return f * 0x10000;
841 This function builds an FT_Fixed from a FIXED. It simply put f.value
842 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
844 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
846 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
850 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
852 Family *family;
853 Face *face;
854 const char *file;
855 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
856 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
858 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
859 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
861 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
863 if(face_name && strcmpiW(face_name, family->FamilyName))
864 continue;
865 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
867 if (!face->file)
868 continue;
869 file = strrchr(face->file, '/');
870 if(!file)
871 file = face->file;
872 else
873 file++;
874 if(!strcasecmp(file, file_nameA))
876 HeapFree(GetProcessHeap(), 0, file_nameA);
877 return face;
881 HeapFree(GetProcessHeap(), 0, file_nameA);
882 return NULL;
885 static Family *find_family_from_name(const WCHAR *name)
887 Family *family;
889 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
891 if(!strcmpiW(family->FamilyName, name))
892 return family;
895 return NULL;
898 static void DumpSubstList(void)
900 FontSubst *psub;
902 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
904 if(psub->from.charset != -1 || psub->to.charset != -1)
905 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
906 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
907 else
908 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
909 debugstr_w(psub->to.name));
911 return;
914 static LPWSTR strdupW(LPCWSTR p)
916 LPWSTR ret;
917 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
918 ret = HeapAlloc(GetProcessHeap(), 0, len);
919 memcpy(ret, p, len);
920 return ret;
923 static LPSTR strdupA(LPCSTR p)
925 LPSTR ret;
926 DWORD len = (strlen(p) + 1);
927 ret = HeapAlloc(GetProcessHeap(), 0, len);
928 memcpy(ret, p, len);
929 return ret;
932 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
933 INT from_charset)
935 FontSubst *element;
937 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
939 if(!strcmpiW(element->from.name, from_name) &&
940 (element->from.charset == from_charset ||
941 element->from.charset == -1))
942 return element;
945 return NULL;
948 #define ADD_FONT_SUBST_FORCE 1
950 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
952 FontSubst *from_exist, *to_exist;
954 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
956 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
958 list_remove(&from_exist->entry);
959 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
960 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
961 HeapFree(GetProcessHeap(), 0, from_exist);
962 from_exist = NULL;
965 if(!from_exist)
967 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
969 if(to_exist)
971 HeapFree(GetProcessHeap(), 0, subst->to.name);
972 subst->to.name = strdupW(to_exist->to.name);
975 list_add_tail(subst_list, &subst->entry);
977 return TRUE;
980 HeapFree(GetProcessHeap(), 0, subst->from.name);
981 HeapFree(GetProcessHeap(), 0, subst->to.name);
982 HeapFree(GetProcessHeap(), 0, subst);
983 return FALSE;
986 static void split_subst_info(NameCs *nc, LPSTR str)
988 CHAR *p = strrchr(str, ',');
989 DWORD len;
991 nc->charset = -1;
992 if(p && *(p+1)) {
993 nc->charset = strtol(p+1, NULL, 10);
994 *p = '\0';
996 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
997 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
998 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1001 static void LoadSubstList(void)
1003 FontSubst *psub;
1004 HKEY hkey;
1005 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1006 LPSTR value;
1007 LPVOID data;
1009 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1010 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1011 &hkey) == ERROR_SUCCESS) {
1013 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1014 &valuelen, &datalen, NULL, NULL);
1016 valuelen++; /* returned value doesn't include room for '\0' */
1017 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1018 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1020 dlen = datalen;
1021 vlen = valuelen;
1022 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1023 &dlen) == ERROR_SUCCESS) {
1024 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1026 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1027 split_subst_info(&psub->from, value);
1028 split_subst_info(&psub->to, data);
1030 /* Win 2000 doesn't allow mapping between different charsets
1031 or mapping of DEFAULT_CHARSET */
1032 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1033 psub->to.charset == DEFAULT_CHARSET) {
1034 HeapFree(GetProcessHeap(), 0, psub->to.name);
1035 HeapFree(GetProcessHeap(), 0, psub->from.name);
1036 HeapFree(GetProcessHeap(), 0, psub);
1037 } else {
1038 add_font_subst(&font_subst_list, psub, 0);
1040 /* reset dlen and vlen */
1041 dlen = datalen;
1042 vlen = valuelen;
1044 HeapFree(GetProcessHeap(), 0, data);
1045 HeapFree(GetProcessHeap(), 0, value);
1046 RegCloseKey(hkey);
1051 /*****************************************************************
1052 * get_name_table_entry
1054 * Supply the platform, encoding, language and name ids in req
1055 * and if the name exists the function will fill in the string
1056 * and string_len members. The string is owned by FreeType so
1057 * don't free it. Returns TRUE if the name is found else FALSE.
1059 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1061 FT_SfntName name;
1062 FT_UInt num_names, name_index;
1064 if(FT_IS_SFNT(ft_face))
1066 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1068 for(name_index = 0; name_index < num_names; name_index++)
1070 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1072 if((name.platform_id == req->platform_id) &&
1073 (name.encoding_id == req->encoding_id) &&
1074 (name.language_id == req->language_id) &&
1075 (name.name_id == req->name_id))
1077 req->string = name.string;
1078 req->string_len = name.string_len;
1079 return TRUE;
1084 req->string = NULL;
1085 req->string_len = 0;
1086 return FALSE;
1089 static WCHAR *get_familyname(FT_Face ft_face)
1091 WCHAR *family = NULL;
1092 FT_SfntName name;
1094 name.platform_id = TT_PLATFORM_MICROSOFT;
1095 name.encoding_id = TT_MS_ID_UNICODE_CS;
1096 name.language_id = GetUserDefaultLCID();
1097 name.name_id = TT_NAME_ID_FONT_FAMILY;
1099 if(get_name_table_entry(ft_face, &name))
1101 FT_UInt i;
1103 /* String is not nul terminated and string_len is a byte length. */
1104 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1105 for(i = 0; i < name.string_len / 2; i++)
1107 WORD *tmp = (WORD *)&name.string[i * 2];
1108 family[i] = GET_BE_WORD(*tmp);
1110 family[i] = 0;
1111 TRACE("Got localised name %s\n", debugstr_w(family));
1114 return family;
1118 /*****************************************************************
1119 * load_sfnt_table
1121 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1122 * of FreeType that don't export this function.
1125 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1128 FT_Error err;
1130 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1131 if(pFT_Load_Sfnt_Table)
1133 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1135 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1136 else /* Do it the hard way */
1138 TT_Face tt_face = (TT_Face) ft_face;
1139 SFNT_Interface *sfnt;
1140 if (FT_Version.major==2 && FT_Version.minor==0)
1142 /* 2.0.x */
1143 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1145 else
1147 /* A field was added in the middle of the structure in 2.1.x */
1148 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1150 err = sfnt->load_any(tt_face, table, offset, buf, len);
1152 #else
1153 else
1155 static int msg;
1156 if(!msg)
1158 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1159 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1160 "Please upgrade your freetype library.\n");
1161 msg++;
1163 err = FT_Err_Unimplemented_Feature;
1165 #endif
1166 return err;
1169 static inline int TestStyles(DWORD flags, DWORD styles)
1171 return (flags & styles) == styles;
1174 static int StyleOrdering(Face *face)
1176 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1177 return 3;
1178 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1179 return 2;
1180 if (TestStyles(face->ntmFlags, NTM_BOLD))
1181 return 1;
1182 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1183 return 0;
1185 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1186 debugstr_w(face->family->FamilyName),
1187 debugstr_w(face->StyleName),
1188 face->ntmFlags);
1190 return 9999;
1193 /* Add a style of face to a font family using an ordering of the list such
1194 that regular fonts come before bold and italic, and single styles come
1195 before compound styles. */
1196 static void AddFaceToFamily(Face *face, Family *family)
1198 struct list *entry;
1200 LIST_FOR_EACH( entry, &family->faces )
1202 Face *ent = LIST_ENTRY(entry, Face, entry);
1203 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1205 list_add_before( entry, &face->entry );
1208 #define ADDFONT_EXTERNAL_FONT 0x01
1209 #define ADDFONT_FORCE_BITMAP 0x02
1210 #define ADDFONT_HIDDEN 0x04
1211 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size,
1212 char *fake_family, const WCHAR *target_family, DWORD flags, Face **face_to_return)
1214 FT_Face ft_face;
1215 TT_OS2 *pOS2;
1216 TT_Header *pHeader = NULL;
1217 WCHAR *english_family, *localised_family, *StyleW;
1218 DWORD len;
1219 Family *family = NULL;
1220 Face *face, *first_face = NULL;
1221 struct list *family_elem_ptr, *face_elem_ptr;
1222 FT_Error err;
1223 FT_Long face_index = 0, num_faces;
1224 #ifdef HAVE_FREETYPE_FTWINFNT_H
1225 FT_WinFNT_HeaderRec winfnt_header;
1226 #endif
1227 int i, bitmap_num, internal_leading;
1228 FONTSIGNATURE fs;
1230 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1231 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1233 #ifdef HAVE_CARBON_CARBON_H
1234 if(file && !fake_family)
1236 char **mac_list = expand_mac_font(file);
1237 if(mac_list)
1239 BOOL had_one = FALSE;
1240 char **cursor;
1241 for(cursor = mac_list; *cursor; cursor++)
1243 had_one = TRUE;
1244 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags, face_to_return);
1245 HeapFree(GetProcessHeap(), 0, *cursor);
1247 HeapFree(GetProcessHeap(), 0, mac_list);
1248 if(had_one)
1249 return 1;
1252 #endif /* HAVE_CARBON_CARBON_H */
1254 do {
1255 char *family_name = fake_family;
1257 if (file)
1259 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1260 err = pFT_New_Face(library, file, face_index, &ft_face);
1261 } else
1263 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1264 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1267 if(err != 0) {
1268 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1269 return 0;
1272 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*/
1273 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1274 pFT_Done_Face(ft_face);
1275 return 0;
1278 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1279 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1280 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1281 pFT_Done_Face(ft_face);
1282 return 0;
1285 if(FT_IS_SFNT(ft_face))
1287 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1288 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1289 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1291 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1292 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1293 pFT_Done_Face(ft_face);
1294 return 0;
1297 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1298 we don't want to load these. */
1299 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1301 FT_ULong len = 0;
1303 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1305 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1306 pFT_Done_Face(ft_face);
1307 return 0;
1312 if(!ft_face->family_name || !ft_face->style_name) {
1313 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1314 pFT_Done_Face(ft_face);
1315 return 0;
1318 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1320 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1321 pFT_Done_Face(ft_face);
1322 return 0;
1325 if (target_family)
1327 localised_family = get_familyname(ft_face);
1328 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1330 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1331 HeapFree(GetProcessHeap(), 0, localised_family);
1332 num_faces = ft_face->num_faces;
1333 pFT_Done_Face(ft_face);
1334 continue;
1336 HeapFree(GetProcessHeap(), 0, localised_family);
1339 if(!family_name)
1340 family_name = ft_face->family_name;
1342 bitmap_num = 0;
1343 do {
1344 My_FT_Bitmap_Size *size = NULL;
1345 FT_ULong tmp_size;
1347 if(!FT_IS_SCALABLE(ft_face))
1348 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1350 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1351 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1352 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1354 internal_leading = 0;
1355 memset(&fs, 0, sizeof(fs));
1357 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1358 if(pOS2) {
1359 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1360 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1361 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1362 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1363 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1364 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1365 if(pOS2->version == 0) {
1366 FT_UInt dummy;
1368 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1369 fs.fsCsb[0] |= FS_LATIN1;
1370 else
1371 fs.fsCsb[0] |= FS_SYMBOL;
1374 #ifdef HAVE_FREETYPE_FTWINFNT_H
1375 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1376 CHARSETINFO csi;
1377 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1378 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1379 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1380 fs = csi.fs;
1381 internal_leading = winfnt_header.internal_leading;
1383 #endif
1385 if (!(flags & ADDFONT_HIDDEN))
1387 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1388 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1389 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1391 localised_family = NULL;
1392 if (!fake_family)
1394 localised_family = get_familyname(ft_face);
1395 if (localised_family && !strcmpiW(localised_family, english_family))
1397 HeapFree(GetProcessHeap(), 0, localised_family);
1398 localised_family = NULL;
1402 family = NULL;
1403 LIST_FOR_EACH(family_elem_ptr, &font_list)
1405 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1406 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1407 break;
1408 family = NULL;
1410 if (!family)
1412 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1413 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1414 list_init(&family->faces);
1415 list_add_tail(&font_list, &family->entry);
1417 if (localised_family)
1419 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1420 subst->from.name = strdupW(english_family);
1421 subst->from.charset = -1;
1422 subst->to.name = strdupW(localised_family);
1423 subst->to.charset = -1;
1424 add_font_subst(&font_subst_list, subst, 0);
1427 HeapFree(GetProcessHeap(), 0, localised_family);
1428 HeapFree(GetProcessHeap(), 0, english_family);
1430 face_elem_ptr = list_head(&family->faces);
1431 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)) )))
1438 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1439 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1440 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1442 if (fake_family)
1444 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1445 HeapFree(GetProcessHeap(), 0, StyleW);
1446 pFT_Done_Face(ft_face);
1447 return 1;
1449 if (!pHeader || pHeader->Font_Revision <= face->font_version)
1451 TRACE("Original font is newer so skipping this one\n");
1452 HeapFree(GetProcessHeap(), 0, StyleW);
1453 pFT_Done_Face(ft_face);
1454 return 1;
1456 else
1458 TRACE("Replacing original with this one\n");
1459 list_remove(&face->entry);
1460 HeapFree(GetProcessHeap(), 0, face->file);
1461 HeapFree(GetProcessHeap(), 0, face->StyleName);
1462 HeapFree(GetProcessHeap(), 0, face);
1463 break;
1469 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1470 face->cached_enum_data = NULL;
1471 face->StyleName = StyleW;
1472 if (file)
1474 face->file = strdupA(file);
1475 face->font_data_ptr = NULL;
1476 face->font_data_size = 0;
1478 else
1480 face->file = NULL;
1481 face->font_data_ptr = font_data_ptr;
1482 face->font_data_size = font_data_size;
1484 face->face_index = face_index;
1485 face->ntmFlags = 0;
1486 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1487 face->ntmFlags |= NTM_ITALIC;
1488 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1489 face->ntmFlags |= NTM_BOLD;
1490 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1491 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1492 face->family = family;
1493 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1494 face->fs = fs;
1495 memset(&face->fs_links, 0, sizeof(face->fs_links));
1497 if(FT_IS_SCALABLE(ft_face)) {
1498 memset(&face->size, 0, sizeof(face->size));
1499 face->scalable = TRUE;
1500 } else {
1501 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1502 size->height, size->width, size->size >> 6,
1503 size->x_ppem >> 6, size->y_ppem >> 6);
1504 face->size.height = size->height;
1505 face->size.width = size->width;
1506 face->size.size = size->size;
1507 face->size.x_ppem = size->x_ppem;
1508 face->size.y_ppem = size->y_ppem;
1509 face->size.internal_leading = internal_leading;
1510 face->scalable = FALSE;
1513 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1514 tmp_size = 0;
1515 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1517 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1518 face->ntmFlags |= NTM_PS_OPENTYPE;
1521 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1522 face->fs.fsCsb[0], face->fs.fsCsb[1],
1523 face->fs.fsUsb[0], face->fs.fsUsb[1],
1524 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1527 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1528 for(i = 0; i < ft_face->num_charmaps; i++) {
1529 switch(ft_face->charmaps[i]->encoding) {
1530 case FT_ENCODING_UNICODE:
1531 case FT_ENCODING_APPLE_ROMAN:
1532 face->fs.fsCsb[0] |= FS_LATIN1;
1533 break;
1534 case FT_ENCODING_MS_SYMBOL:
1535 face->fs.fsCsb[0] |= FS_SYMBOL;
1536 break;
1537 default:
1538 break;
1543 if (!(flags & ADDFONT_HIDDEN))
1545 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1546 have_installed_roman_font = TRUE;
1548 AddFaceToFamily(face, family);
1551 if (!first_face) first_face = face;
1552 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1554 num_faces = ft_face->num_faces;
1555 pFT_Done_Face(ft_face);
1556 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1557 debugstr_w(StyleW));
1558 } while(num_faces > ++face_index);
1560 if (face_to_return) *face_to_return = first_face;
1562 return num_faces;
1565 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags, Face **face_to_return)
1567 return AddFontToList(file, NULL, 0, fake_family, target_family, flags, face_to_return);
1570 static void DumpFontList(void)
1572 Family *family;
1573 Face *face;
1574 struct list *family_elem_ptr, *face_elem_ptr;
1576 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1577 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1578 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1579 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1580 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1581 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1582 if(!face->scalable)
1583 TRACE(" %d", face->size.height);
1584 TRACE("\n");
1587 return;
1590 /***********************************************************
1591 * The replacement list is a way to map an entire font
1592 * family onto another family. For example adding
1594 * [HKCU\Software\Wine\Fonts\Replacements]
1595 * "Wingdings"="Winedings"
1597 * would enumerate the Winedings font both as Winedings and
1598 * Wingdings. However if a real Wingdings font is present the
1599 * replacement does not take place.
1602 static void LoadReplaceList(void)
1604 HKEY hkey;
1605 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1606 LPWSTR value;
1607 LPVOID data;
1608 Family *family;
1609 Face *face;
1610 struct list *family_elem_ptr, *face_elem_ptr;
1611 CHAR familyA[400];
1613 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1614 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1616 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1617 &valuelen, &datalen, NULL, NULL);
1619 valuelen++; /* returned value doesn't include room for '\0' */
1620 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1621 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1623 dlen = datalen;
1624 vlen = valuelen;
1625 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1626 &dlen) == ERROR_SUCCESS) {
1627 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1628 /* "NewName"="Oldname" */
1629 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1631 /* Find the old family and hence all of the font files
1632 in that family */
1633 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1634 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1635 if(!strcmpiW(family->FamilyName, data)) {
1636 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1637 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1638 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1639 debugstr_w(face->StyleName), familyA);
1640 /* Now add a new entry with the new family name */
1641 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0), NULL);
1643 break;
1646 /* reset dlen and vlen */
1647 dlen = datalen;
1648 vlen = valuelen;
1650 HeapFree(GetProcessHeap(), 0, data);
1651 HeapFree(GetProcessHeap(), 0, value);
1652 RegCloseKey(hkey);
1656 /*************************************************************
1657 * init_system_links
1659 static BOOL init_system_links(void)
1661 HKEY hkey;
1662 BOOL ret = FALSE;
1663 DWORD type, max_val, max_data, val_len, data_len, index;
1664 WCHAR *value, *data;
1665 WCHAR *entry, *next;
1666 SYSTEM_LINKS *font_link, *system_font_link;
1667 CHILD_FONT *child_font;
1668 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1669 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1670 FONTSIGNATURE fs;
1671 Family *family;
1672 Face *face;
1673 FontSubst *psub;
1675 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1677 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1678 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1679 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1680 val_len = max_val + 1;
1681 data_len = max_data;
1682 index = 0;
1683 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1685 memset(&fs, 0, sizeof(fs));
1686 psub = get_font_subst(&font_subst_list, value, -1);
1687 /* Don't store fonts that are only substitutes for other fonts */
1688 if(psub)
1690 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1691 goto next;
1693 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1694 font_link->font_name = strdupW(value);
1695 list_init(&font_link->links);
1696 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1698 WCHAR *face_name;
1699 CHILD_FONT *child_font;
1701 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1703 next = entry + strlenW(entry) + 1;
1705 face_name = strchrW(entry, ',');
1706 if(face_name)
1708 *face_name++ = 0;
1709 while(isspaceW(*face_name))
1710 face_name++;
1712 psub = get_font_subst(&font_subst_list, face_name, -1);
1713 if(psub)
1714 face_name = psub->to.name;
1716 face = find_face_from_filename(entry, face_name);
1717 if(!face)
1719 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1720 continue;
1723 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1724 child_font->face = face;
1725 child_font->font = NULL;
1726 fs.fsCsb[0] |= face->fs.fsCsb[0];
1727 fs.fsCsb[1] |= face->fs.fsCsb[1];
1728 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1729 list_add_tail(&font_link->links, &child_font->entry);
1731 family = find_family_from_name(font_link->font_name);
1732 if(family)
1734 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1736 face->fs_links = fs;
1739 list_add_tail(&system_links, &font_link->entry);
1740 next:
1741 val_len = max_val + 1;
1742 data_len = max_data;
1745 HeapFree(GetProcessHeap(), 0, value);
1746 HeapFree(GetProcessHeap(), 0, data);
1747 RegCloseKey(hkey);
1750 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1751 that Tahoma has */
1753 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1754 system_font_link->font_name = strdupW(System);
1755 list_init(&system_font_link->links);
1757 face = find_face_from_filename(tahoma_ttf, Tahoma);
1758 if(face)
1760 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1761 child_font->face = face;
1762 child_font->font = NULL;
1763 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1764 list_add_tail(&system_font_link->links, &child_font->entry);
1766 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1768 if(!strcmpiW(font_link->font_name, Tahoma))
1770 CHILD_FONT *font_link_entry;
1771 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1773 CHILD_FONT *new_child;
1774 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1775 new_child->face = font_link_entry->face;
1776 new_child->font = NULL;
1777 list_add_tail(&system_font_link->links, &new_child->entry);
1779 break;
1782 list_add_tail(&system_links, &system_font_link->entry);
1783 return ret;
1786 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1788 DIR *dir;
1789 struct dirent *dent;
1790 char path[MAX_PATH];
1792 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1794 dir = opendir(dirname);
1795 if(!dir) {
1796 WARN("Can't open directory %s\n", debugstr_a(dirname));
1797 return FALSE;
1799 while((dent = readdir(dir)) != NULL) {
1800 struct stat statbuf;
1802 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1803 continue;
1805 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1807 sprintf(path, "%s/%s", dirname, dent->d_name);
1809 if(stat(path, &statbuf) == -1)
1811 WARN("Can't stat %s\n", debugstr_a(path));
1812 continue;
1814 if(S_ISDIR(statbuf.st_mode))
1815 ReadFontDir(path, external_fonts);
1816 else
1817 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0, NULL);
1819 closedir(dir);
1820 return TRUE;
1823 static void load_fontconfig_fonts(void)
1825 #ifdef SONAME_LIBFONTCONFIG
1826 void *fc_handle = NULL;
1827 FcConfig *config;
1828 FcPattern *pat;
1829 FcObjectSet *os;
1830 FcFontSet *fontset;
1831 int i, len;
1832 char *file;
1833 const char *ext;
1835 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1836 if(!fc_handle) {
1837 TRACE("Wine cannot find the fontconfig library (%s).\n",
1838 SONAME_LIBFONTCONFIG);
1839 return;
1841 #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;}
1842 LOAD_FUNCPTR(FcConfigGetCurrent);
1843 LOAD_FUNCPTR(FcFontList);
1844 LOAD_FUNCPTR(FcFontSetDestroy);
1845 LOAD_FUNCPTR(FcInit);
1846 LOAD_FUNCPTR(FcObjectSetAdd);
1847 LOAD_FUNCPTR(FcObjectSetCreate);
1848 LOAD_FUNCPTR(FcObjectSetDestroy);
1849 LOAD_FUNCPTR(FcPatternCreate);
1850 LOAD_FUNCPTR(FcPatternDestroy);
1851 LOAD_FUNCPTR(FcPatternGetBool);
1852 LOAD_FUNCPTR(FcPatternGetString);
1853 #undef LOAD_FUNCPTR
1855 if(!pFcInit()) return;
1857 config = pFcConfigGetCurrent();
1858 pat = pFcPatternCreate();
1859 os = pFcObjectSetCreate();
1860 pFcObjectSetAdd(os, FC_FILE);
1861 pFcObjectSetAdd(os, FC_SCALABLE);
1862 fontset = pFcFontList(config, pat, os);
1863 if(!fontset) return;
1864 for(i = 0; i < fontset->nfont; i++) {
1865 FcBool scalable;
1867 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1868 continue;
1869 TRACE("fontconfig: %s\n", file);
1871 /* We're just interested in OT/TT fonts for now, so this hack just
1872 picks up the scalable fonts without extensions .pf[ab] to save time
1873 loading every other font */
1875 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1877 TRACE("not scalable\n");
1878 continue;
1881 len = strlen( file );
1882 if(len < 4) continue;
1883 ext = &file[ len - 3 ];
1884 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1885 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT, NULL);
1887 pFcFontSetDestroy(fontset);
1888 pFcObjectSetDestroy(os);
1889 pFcPatternDestroy(pat);
1890 sym_not_found:
1891 #endif
1892 return;
1895 static BOOL load_font_from_data_dir(LPCWSTR file)
1897 BOOL ret = FALSE;
1898 const char *data_dir = wine_get_data_dir();
1900 if (!data_dir) data_dir = wine_get_build_dir();
1902 if (data_dir)
1904 INT len;
1905 char *unix_name;
1907 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1909 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1911 strcpy(unix_name, data_dir);
1912 strcat(unix_name, "/fonts/");
1914 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1916 EnterCriticalSection( &freetype_cs );
1917 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP, NULL);
1918 LeaveCriticalSection( &freetype_cs );
1919 HeapFree(GetProcessHeap(), 0, unix_name);
1921 return ret;
1924 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1926 static const WCHAR slashW[] = {'\\','\0'};
1927 BOOL ret = FALSE;
1928 WCHAR windowsdir[MAX_PATH];
1929 char *unixname;
1931 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1932 strcatW(windowsdir, fontsW);
1933 strcatW(windowsdir, slashW);
1934 strcatW(windowsdir, file);
1935 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1936 EnterCriticalSection( &freetype_cs );
1937 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP, NULL);
1938 LeaveCriticalSection( &freetype_cs );
1939 HeapFree(GetProcessHeap(), 0, unixname);
1941 return ret;
1944 static void load_system_fonts(void)
1946 HKEY hkey;
1947 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1948 const WCHAR * const *value;
1949 DWORD dlen, type;
1950 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1951 char *unixname;
1953 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1954 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1955 strcatW(windowsdir, fontsW);
1956 for(value = SystemFontValues; *value; value++) {
1957 dlen = sizeof(data);
1958 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1959 type == REG_SZ) {
1960 BOOL added = FALSE;
1962 sprintfW(pathW, fmtW, windowsdir, data);
1963 if((unixname = wine_get_unix_file_name(pathW))) {
1964 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP, NULL);
1965 HeapFree(GetProcessHeap(), 0, unixname);
1967 if (!added)
1968 load_font_from_data_dir(data);
1971 RegCloseKey(hkey);
1975 /*************************************************************
1977 * This adds registry entries for any externally loaded fonts
1978 * (fonts from fontconfig or FontDirs). It also deletes entries
1979 * of no longer existing fonts.
1982 static void update_reg_entries(void)
1984 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1985 LPWSTR valueW;
1986 DWORD len, len_fam;
1987 Family *family;
1988 Face *face;
1989 struct list *family_elem_ptr, *face_elem_ptr;
1990 WCHAR *file;
1991 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1992 static const WCHAR spaceW[] = {' ', '\0'};
1993 char *path;
1995 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1996 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1997 ERR("Can't create Windows font reg key\n");
1998 goto end;
2001 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2002 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2003 ERR("Can't create Windows font reg key\n");
2004 goto end;
2007 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2008 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2009 ERR("Can't create external font reg key\n");
2010 goto end;
2013 /* enumerate the fonts and add external ones to the two keys */
2015 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2016 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2017 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2018 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2019 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2020 if(!face->external) continue;
2021 len = len_fam;
2022 if (!(face->ntmFlags & NTM_REGULAR))
2023 len = len_fam + strlenW(face->StyleName) + 1;
2024 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2025 strcpyW(valueW, family->FamilyName);
2026 if(len != len_fam) {
2027 strcatW(valueW, spaceW);
2028 strcatW(valueW, face->StyleName);
2030 strcatW(valueW, TrueType);
2032 file = wine_get_dos_file_name(face->file);
2033 if(file)
2034 len = strlenW(file) + 1;
2035 else
2037 if((path = strrchr(face->file, '/')) == NULL)
2038 path = face->file;
2039 else
2040 path++;
2041 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2043 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2044 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2046 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2047 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2048 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2050 HeapFree(GetProcessHeap(), 0, file);
2051 HeapFree(GetProcessHeap(), 0, valueW);
2054 end:
2055 if(external_key) RegCloseKey(external_key);
2056 if(win9x_key) RegCloseKey(win9x_key);
2057 if(winnt_key) RegCloseKey(winnt_key);
2058 return;
2061 static void delete_external_font_keys(void)
2063 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2064 DWORD dlen, vlen, datalen, valuelen, i, type;
2065 LPWSTR valueW;
2066 LPVOID data;
2068 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2069 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2070 ERR("Can't create Windows font reg key\n");
2071 goto end;
2074 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2075 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2076 ERR("Can't create Windows font reg key\n");
2077 goto end;
2080 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2081 ERR("Can't create external font reg key\n");
2082 goto end;
2085 /* Delete all external fonts added last time */
2087 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2088 &valuelen, &datalen, NULL, NULL);
2089 valuelen++; /* returned value doesn't include room for '\0' */
2090 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2091 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2093 dlen = datalen * sizeof(WCHAR);
2094 vlen = valuelen;
2095 i = 0;
2096 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2097 &dlen) == ERROR_SUCCESS) {
2099 RegDeleteValueW(winnt_key, valueW);
2100 RegDeleteValueW(win9x_key, valueW);
2101 /* reset dlen and vlen */
2102 dlen = datalen;
2103 vlen = valuelen;
2105 HeapFree(GetProcessHeap(), 0, data);
2106 HeapFree(GetProcessHeap(), 0, valueW);
2108 /* Delete the old external fonts key */
2109 RegCloseKey(external_key);
2110 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2112 end:
2113 if(win9x_key) RegCloseKey(win9x_key);
2114 if(winnt_key) RegCloseKey(winnt_key);
2117 /*************************************************************
2118 * WineEngAddFontResourceEx
2121 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2123 INT ret = 0;
2125 GDI_CheckNotLock();
2127 if (ft_handle) /* do it only if we have freetype up and running */
2129 char *unixname;
2131 if(flags)
2132 FIXME("Ignoring flags %x\n", flags);
2134 if((unixname = wine_get_unix_file_name(file)))
2136 EnterCriticalSection( &freetype_cs );
2137 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP, NULL);
2138 LeaveCriticalSection( &freetype_cs );
2139 HeapFree(GetProcessHeap(), 0, unixname);
2141 if (!ret && !strchrW(file, '\\')) {
2142 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2143 ret = load_font_from_winfonts_dir(file);
2144 if (!ret) {
2145 /* Try in datadir/fonts (or builddir/fonts),
2146 * needed for Magic the Gathering Online
2148 ret = load_font_from_data_dir(file);
2152 return ret;
2155 /*************************************************************
2156 * WineEngAddFontMemResourceEx
2159 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2161 GDI_CheckNotLock();
2163 if (ft_handle) /* do it only if we have freetype up and running */
2165 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2167 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2168 memcpy(pFontCopy, pbFont, cbFont);
2170 EnterCriticalSection( &freetype_cs );
2171 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP, NULL);
2172 LeaveCriticalSection( &freetype_cs );
2174 if (*pcFonts == 0)
2176 TRACE("AddFontToList failed\n");
2177 HeapFree(GetProcessHeap(), 0, pFontCopy);
2178 return 0;
2180 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2181 * For now return something unique but quite random
2183 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2184 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2187 *pcFonts = 0;
2188 return 0;
2191 /*************************************************************
2192 * WineEngRemoveFontResourceEx
2195 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2197 GDI_CheckNotLock();
2198 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2199 return TRUE;
2202 static const struct nls_update_font_list
2204 UINT ansi_cp, oem_cp;
2205 const char *oem, *fixed, *system;
2206 const char *courier, *serif, *small, *sserif;
2207 /* these are for font substitutes */
2208 const char *shelldlg, *tmsrmn;
2209 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2210 *helv_0, *tmsrmn_0;
2211 const struct subst
2213 const char *from, *to;
2214 } arial_0, courier_new_0, times_new_roman_0;
2215 } nls_update_font_list[] =
2217 /* Latin 1 (United States) */
2218 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2219 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2220 "Tahoma","Times New Roman",
2221 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2222 { 0 }, { 0 }, { 0 }
2224 /* Latin 1 (Multilingual) */
2225 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2226 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2229 { 0 }, { 0 }, { 0 }
2231 /* Eastern Europe */
2232 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2233 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2234 "Tahoma","Times New Roman", /* FIXME unverified */
2235 "Fixedsys,238", "System,238",
2236 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2237 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2238 { "Arial CE,0", "Arial,238" },
2239 { "Courier New CE,0", "Courier New,238" },
2240 { "Times New Roman CE,0", "Times New Roman,238" }
2242 /* Cyrillic */
2243 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2244 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,204", "System,204",
2247 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2248 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2249 { "Arial Cyr,0", "Arial,204" },
2250 { "Courier New Cyr,0", "Courier New,204" },
2251 { "Times New Roman Cyr,0", "Times New Roman,204" }
2253 /* Greek */
2254 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2255 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 "Fixedsys,161", "System,161",
2258 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2259 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2260 { "Arial Greek,0", "Arial,161" },
2261 { "Courier New Greek,0", "Courier New,161" },
2262 { "Times New Roman Greek,0", "Times New Roman,161" }
2264 /* Turkish */
2265 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2266 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2267 "Tahoma","Times New Roman", /* FIXME unverified */
2268 "Fixedsys,162", "System,162",
2269 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2270 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2271 { "Arial Tur,0", "Arial,162" },
2272 { "Courier New Tur,0", "Courier New,162" },
2273 { "Times New Roman Tur,0", "Times New Roman,162" }
2275 /* Hebrew */
2276 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2277 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 "Fixedsys,177", "System,177",
2280 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2281 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2282 { 0 }, { 0 }, { 0 }
2284 /* Arabic */
2285 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2286 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2287 "Tahoma","Times New Roman", /* FIXME unverified */
2288 "Fixedsys,178", "System,178",
2289 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2290 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2291 { 0 }, { 0 }, { 0 }
2293 /* Baltic */
2294 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2295 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2296 "Tahoma","Times New Roman", /* FIXME unverified */
2297 "Fixedsys,186", "System,186",
2298 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2299 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2300 { "Arial Baltic,0", "Arial,186" },
2301 { "Courier New Baltic,0", "Courier New,186" },
2302 { "Times New Roman Baltic,0", "Times New Roman,186" }
2304 /* Vietnamese */
2305 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2306 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2307 "Tahoma","Times New Roman", /* FIXME unverified */
2308 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2309 { 0 }, { 0 }, { 0 }
2311 /* Thai */
2312 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2313 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2314 "Tahoma","Times New Roman", /* FIXME unverified */
2315 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2316 { 0 }, { 0 }, { 0 }
2318 /* Japanese */
2319 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2320 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2321 "MS UI Gothic","MS Serif",
2322 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2323 { 0 }, { 0 }, { 0 }
2325 /* Chinese Simplified */
2326 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2327 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2328 "SimSun", "NSimSun",
2329 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2330 { 0 }, { 0 }, { 0 }
2332 /* Korean */
2333 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2334 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2335 "Gulim", "Batang",
2336 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2337 { 0 }, { 0 }, { 0 }
2339 /* Chinese Traditional */
2340 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2341 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2342 "PMingLiU", "MingLiU",
2343 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2344 { 0 }, { 0 }, { 0 }
2348 static const WCHAR *font_links_list[] =
2350 Lucida_Sans_Unicode,
2351 Microsoft_Sans_Serif,
2352 Tahoma
2355 static const struct font_links_defaults_list
2357 /* Keyed off substitution for "MS Shell Dlg" */
2358 const WCHAR *shelldlg;
2359 /* Maximum of four substitutes, plus terminating NULL pointer */
2360 const WCHAR *substitutes[5];
2361 } font_links_defaults_list[] =
2363 /* Non East-Asian */
2364 { Tahoma, /* FIXME unverified ordering */
2365 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2367 /* Below lists are courtesy of
2368 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2370 /* Japanese */
2371 { MS_UI_Gothic,
2372 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2374 /* Chinese Simplified */
2375 { SimSun,
2376 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2378 /* Korean */
2379 { Gulim,
2380 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2382 /* Chinese Traditional */
2383 { PMingLiU,
2384 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2388 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2390 return ( ansi_cp == 932 /* CP932 for Japanese */
2391 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2392 || ansi_cp == 949 /* CP949 for Korean */
2393 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2396 static inline HKEY create_fonts_NT_registry_key(void)
2398 HKEY hkey = 0;
2400 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2401 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2402 return hkey;
2405 static inline HKEY create_fonts_9x_registry_key(void)
2407 HKEY hkey = 0;
2409 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2410 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2411 return hkey;
2414 static inline HKEY create_config_fonts_registry_key(void)
2416 HKEY hkey = 0;
2418 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2419 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2420 return hkey;
2423 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2425 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2426 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2427 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2428 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2431 static void set_value_key(HKEY hkey, const char *name, const char *value)
2433 if (value)
2434 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2435 else if (name)
2436 RegDeleteValueA(hkey, name);
2439 static void update_font_info(void)
2441 char buf[40], cpbuf[40];
2442 DWORD len, type;
2443 HKEY hkey = 0;
2444 UINT i, ansi_cp = 0, oem_cp = 0;
2445 BOOL done = FALSE;
2447 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2448 return;
2450 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2451 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2452 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2453 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2454 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2456 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2457 if (is_dbcs_ansi_cp(ansi_cp))
2458 use_default_fallback = TRUE;
2460 len = sizeof(buf);
2461 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2463 if (!strcmp( buf, cpbuf )) /* already set correctly */
2465 RegCloseKey(hkey);
2466 return;
2468 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2470 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2472 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2473 RegCloseKey(hkey);
2475 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2477 HKEY hkey;
2479 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2480 nls_update_font_list[i].oem_cp == oem_cp)
2482 hkey = create_config_fonts_registry_key();
2483 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2484 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2485 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2486 RegCloseKey(hkey);
2488 hkey = create_fonts_NT_registry_key();
2489 add_font_list(hkey, &nls_update_font_list[i]);
2490 RegCloseKey(hkey);
2492 hkey = create_fonts_9x_registry_key();
2493 add_font_list(hkey, &nls_update_font_list[i]);
2494 RegCloseKey(hkey);
2496 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2498 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2499 strlen(nls_update_font_list[i].shelldlg)+1);
2500 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2501 strlen(nls_update_font_list[i].tmsrmn)+1);
2503 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2504 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2505 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2506 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2507 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2508 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2509 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2510 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2512 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2513 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2514 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2516 RegCloseKey(hkey);
2518 done = TRUE;
2520 else
2522 /* Delete the FontSubstitutes from other locales */
2523 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2525 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2526 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2527 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2528 RegCloseKey(hkey);
2532 if (!done)
2533 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2535 /* Clear out system links */
2536 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2539 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2541 const WCHAR *value;
2542 int i;
2543 FontSubst *psub;
2544 Family *family;
2545 Face *face;
2546 const char *file;
2547 WCHAR *fileW;
2548 int fileLen;
2549 WCHAR buff[MAX_PATH];
2550 WCHAR *data;
2551 int entryLen;
2553 static const WCHAR comma[] = {',',0};
2555 RegDeleteValueW(hkey, name);
2556 if (values)
2558 data = buff;
2559 data[0] = '\0';
2560 for (i = 0; values[i] != NULL; i++)
2562 value = values[i];
2563 if (!strcmpiW(name,value))
2564 continue;
2565 psub = get_font_subst(&font_subst_list, value, -1);
2566 if(psub)
2567 value = psub->to.name;
2568 family = find_family_from_name(value);
2569 if (!family)
2570 continue;
2571 file = NULL;
2572 /* Use first extant filename for this Family */
2573 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2575 if (!face->file)
2576 continue;
2577 file = strrchr(face->file, '/');
2578 if (!file)
2579 file = face->file;
2580 else
2581 file++;
2582 break;
2584 if (!file)
2585 continue;
2586 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2587 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2588 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2589 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2590 if (sizeof(buff)-(data-buff) < entryLen + 1)
2592 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2593 HeapFree(GetProcessHeap(), 0, fileW);
2594 break;
2596 strcpyW(data, fileW);
2597 strcatW(data, comma);
2598 strcatW(data, value);
2599 data += entryLen;
2600 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2601 HeapFree(GetProcessHeap(), 0, fileW);
2603 if (data != buff)
2605 *data='\0';
2606 data++;
2607 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2608 } else
2609 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2610 } else
2611 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2614 static void update_system_links(void)
2616 HKEY hkey = 0;
2617 UINT i, j;
2618 BOOL done = FALSE;
2619 DWORD disposition;
2620 FontSubst *psub;
2622 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2624 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2626 if (disposition == REG_OPENED_EXISTING_KEY)
2628 TRACE("SystemLink key already exists, doing nothing\n");
2629 RegCloseKey(hkey);
2630 return;
2633 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2634 if (!psub) {
2635 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2636 RegCloseKey(hkey);
2637 return;
2640 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2642 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2644 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2645 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2647 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2648 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2649 done = TRUE;
2651 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2653 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2656 RegCloseKey(hkey);
2657 if (!done)
2658 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2659 } else
2660 WARN("failed to create SystemLink key\n");
2664 static BOOL init_freetype(void)
2666 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2667 if(!ft_handle) {
2668 WINE_MESSAGE(
2669 "Wine cannot find the FreeType font library. To enable Wine to\n"
2670 "use TrueType fonts please install a version of FreeType greater than\n"
2671 "or equal to 2.0.5.\n"
2672 "http://www.freetype.org\n");
2673 return FALSE;
2676 #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;}
2678 LOAD_FUNCPTR(FT_Vector_Unit)
2679 LOAD_FUNCPTR(FT_Done_Face)
2680 LOAD_FUNCPTR(FT_Get_Char_Index)
2681 LOAD_FUNCPTR(FT_Get_Module)
2682 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2683 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2684 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2685 LOAD_FUNCPTR(FT_Init_FreeType)
2686 LOAD_FUNCPTR(FT_Load_Glyph)
2687 LOAD_FUNCPTR(FT_Matrix_Multiply)
2688 #ifndef FT_MULFIX_INLINED
2689 LOAD_FUNCPTR(FT_MulFix)
2690 #endif
2691 LOAD_FUNCPTR(FT_New_Face)
2692 LOAD_FUNCPTR(FT_New_Memory_Face)
2693 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2694 LOAD_FUNCPTR(FT_Outline_Transform)
2695 LOAD_FUNCPTR(FT_Outline_Translate)
2696 LOAD_FUNCPTR(FT_Select_Charmap)
2697 LOAD_FUNCPTR(FT_Set_Charmap)
2698 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2699 LOAD_FUNCPTR(FT_Vector_Transform)
2700 LOAD_FUNCPTR(FT_Render_Glyph)
2702 #undef LOAD_FUNCPTR
2703 /* Don't warn if these ones are missing */
2704 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2705 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2706 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2707 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2708 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2709 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2710 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2711 #endif
2712 #ifdef HAVE_FREETYPE_FTWINFNT_H
2713 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2714 #endif
2715 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2716 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2717 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2718 <= 2.0.3 has FT_Sqrt64 */
2719 goto sym_not_found;
2722 if(pFT_Init_FreeType(&library) != 0) {
2723 ERR("Can't init FreeType library\n");
2724 wine_dlclose(ft_handle, NULL, 0);
2725 ft_handle = NULL;
2726 return FALSE;
2728 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2729 if (pFT_Library_Version)
2730 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2732 if (FT_Version.major<=0)
2734 FT_Version.major=2;
2735 FT_Version.minor=0;
2736 FT_Version.patch=5;
2738 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2739 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2740 ((FT_Version.minor << 8) & 0x00ff00) |
2741 ((FT_Version.patch ) & 0x0000ff);
2743 return TRUE;
2745 sym_not_found:
2746 WINE_MESSAGE(
2747 "Wine cannot find certain functions that it needs inside the FreeType\n"
2748 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2749 "FreeType to at least version 2.0.5.\n"
2750 "http://www.freetype.org\n");
2751 wine_dlclose(ft_handle, NULL, 0);
2752 ft_handle = NULL;
2753 return FALSE;
2756 /*************************************************************
2757 * WineEngInit
2759 * Initialize FreeType library and create a list of available faces
2761 BOOL WineEngInit(void)
2763 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2764 static const WCHAR pathW[] = {'P','a','t','h',0};
2765 HKEY hkey;
2766 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2767 WCHAR windowsdir[MAX_PATH];
2768 char *unixname;
2769 HANDLE font_mutex;
2770 const char *data_dir;
2772 TRACE("\n");
2774 /* update locale dependent font info in registry */
2775 update_font_info();
2777 if(!init_freetype()) return FALSE;
2779 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2780 ERR("Failed to create font mutex\n");
2781 return FALSE;
2783 WaitForSingleObject(font_mutex, INFINITE);
2785 delete_external_font_keys();
2787 /* load the system bitmap fonts */
2788 load_system_fonts();
2790 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2791 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2792 strcatW(windowsdir, fontsW);
2793 if((unixname = wine_get_unix_file_name(windowsdir)))
2795 ReadFontDir(unixname, FALSE);
2796 HeapFree(GetProcessHeap(), 0, unixname);
2799 /* load the system truetype fonts */
2800 data_dir = wine_get_data_dir();
2801 if (!data_dir) data_dir = wine_get_build_dir();
2802 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2803 strcpy(unixname, data_dir);
2804 strcat(unixname, "/fonts/");
2805 ReadFontDir(unixname, TRUE);
2806 HeapFree(GetProcessHeap(), 0, unixname);
2809 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2810 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2811 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2812 will skip these. */
2813 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2814 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2815 &hkey) == ERROR_SUCCESS) {
2816 LPWSTR data, valueW;
2817 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2818 &valuelen, &datalen, NULL, NULL);
2820 valuelen++; /* returned value doesn't include room for '\0' */
2821 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2822 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2823 if (valueW && data)
2825 dlen = datalen * sizeof(WCHAR);
2826 vlen = valuelen;
2827 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2828 &dlen) == ERROR_SUCCESS) {
2829 if(data[0] && (data[1] == ':'))
2831 if((unixname = wine_get_unix_file_name(data)))
2833 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP, NULL);
2834 HeapFree(GetProcessHeap(), 0, unixname);
2837 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2839 WCHAR pathW[MAX_PATH];
2840 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2841 BOOL added = FALSE;
2843 sprintfW(pathW, fmtW, windowsdir, data);
2844 if((unixname = wine_get_unix_file_name(pathW)))
2846 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP, NULL);
2847 HeapFree(GetProcessHeap(), 0, unixname);
2849 if (!added)
2850 load_font_from_data_dir(data);
2852 /* reset dlen and vlen */
2853 dlen = datalen;
2854 vlen = valuelen;
2857 HeapFree(GetProcessHeap(), 0, data);
2858 HeapFree(GetProcessHeap(), 0, valueW);
2859 RegCloseKey(hkey);
2862 load_fontconfig_fonts();
2864 /* then look in any directories that we've specified in the config file */
2865 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2866 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2868 DWORD len;
2869 LPWSTR valueW;
2870 LPSTR valueA, ptr;
2872 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2874 len += sizeof(WCHAR);
2875 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2876 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2878 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2879 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2880 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2881 TRACE( "got font path %s\n", debugstr_a(valueA) );
2882 ptr = valueA;
2883 while (ptr)
2885 LPSTR next = strchr( ptr, ':' );
2886 if (next) *next++ = 0;
2887 ReadFontDir( ptr, TRUE );
2888 ptr = next;
2890 HeapFree( GetProcessHeap(), 0, valueA );
2892 HeapFree( GetProcessHeap(), 0, valueW );
2894 RegCloseKey(hkey);
2897 DumpFontList();
2898 LoadSubstList();
2899 DumpSubstList();
2900 LoadReplaceList();
2901 update_reg_entries();
2903 update_system_links();
2904 init_system_links();
2906 ReleaseMutex(font_mutex);
2907 return TRUE;
2911 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2913 TT_OS2 *pOS2;
2914 TT_HoriHeader *pHori;
2916 LONG ppem;
2918 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2919 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2921 if(height == 0) height = 16;
2923 /* Calc. height of EM square:
2925 * For +ve lfHeight we have
2926 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2927 * Re-arranging gives:
2928 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2930 * For -ve lfHeight we have
2931 * |lfHeight| = ppem
2932 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2933 * with il = winAscent + winDescent - units_per_em]
2937 if(height > 0) {
2938 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2939 ppem = MulDiv(ft_face->units_per_EM, height,
2940 pHori->Ascender - pHori->Descender);
2941 else
2942 ppem = MulDiv(ft_face->units_per_EM, height,
2943 pOS2->usWinAscent + pOS2->usWinDescent);
2945 else
2946 ppem = -height;
2948 return ppem;
2951 static struct font_mapping *map_font_file( const char *name )
2953 struct font_mapping *mapping;
2954 struct stat st;
2955 int fd;
2957 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2958 if (fstat( fd, &st ) == -1) goto error;
2960 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2962 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2964 mapping->refcount++;
2965 close( fd );
2966 return mapping;
2969 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2970 goto error;
2972 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2973 close( fd );
2975 if (mapping->data == MAP_FAILED)
2977 HeapFree( GetProcessHeap(), 0, mapping );
2978 return NULL;
2980 mapping->refcount = 1;
2981 mapping->dev = st.st_dev;
2982 mapping->ino = st.st_ino;
2983 mapping->size = st.st_size;
2984 list_add_tail( &mappings_list, &mapping->entry );
2985 return mapping;
2987 error:
2988 close( fd );
2989 return NULL;
2992 static void unmap_font_file( struct font_mapping *mapping )
2994 if (!--mapping->refcount)
2996 list_remove( &mapping->entry );
2997 munmap( mapping->data, mapping->size );
2998 HeapFree( GetProcessHeap(), 0, mapping );
3002 static LONG load_VDMX(GdiFont*, LONG);
3004 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3006 FT_Error err;
3007 FT_Face ft_face;
3008 void *data_ptr;
3009 DWORD data_size;
3011 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3013 if (face->file)
3015 if (!(font->mapping = map_font_file( face->file )))
3017 WARN("failed to map %s\n", debugstr_a(face->file));
3018 return 0;
3020 data_ptr = font->mapping->data;
3021 data_size = font->mapping->size;
3023 else
3025 data_ptr = face->font_data_ptr;
3026 data_size = face->font_data_size;
3029 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3030 if(err) {
3031 ERR("FT_New_Face rets %d\n", err);
3032 return 0;
3035 /* set it here, as load_VDMX needs it */
3036 font->ft_face = ft_face;
3038 if(FT_IS_SCALABLE(ft_face)) {
3039 /* load the VDMX table if we have one */
3040 font->ppem = load_VDMX(font, height);
3041 if(font->ppem == 0)
3042 font->ppem = calc_ppem_for_height(ft_face, height);
3043 TRACE("height %d => ppem %d\n", height, font->ppem);
3045 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3046 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3047 } else {
3048 font->ppem = height;
3049 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3050 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3052 return ft_face;
3056 static int get_nearest_charset(Face *face, int *cp)
3058 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3059 a single face with the requested charset. The idea is to check if
3060 the selected font supports the current ANSI codepage, if it does
3061 return the corresponding charset, else return the first charset */
3063 CHARSETINFO csi;
3064 int acp = GetACP(), i;
3065 DWORD fs0;
3067 *cp = acp;
3068 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3069 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3070 return csi.ciCharset;
3072 for(i = 0; i < 32; i++) {
3073 fs0 = 1L << i;
3074 if(face->fs.fsCsb[0] & fs0) {
3075 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3076 *cp = csi.ciACP;
3077 return csi.ciCharset;
3079 else
3080 FIXME("TCI failing on %x\n", fs0);
3084 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3085 face->fs.fsCsb[0], face->file);
3086 *cp = acp;
3087 return DEFAULT_CHARSET;
3090 static GdiFont *alloc_font(void)
3092 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3093 ret->gmsize = 1;
3094 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3095 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3096 ret->potm = NULL;
3097 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3098 ret->total_kern_pairs = (DWORD)-1;
3099 ret->kern_pairs = NULL;
3100 list_init(&ret->hfontlist);
3101 list_init(&ret->child_fonts);
3102 return ret;
3105 static void free_font(GdiFont *font)
3107 struct list *cursor, *cursor2;
3108 DWORD i;
3110 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3112 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3113 struct list *first_hfont;
3114 HFONTLIST *hfontlist;
3115 list_remove(cursor);
3116 if(child->font)
3118 first_hfont = list_head(&child->font->hfontlist);
3119 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3120 DeleteObject(hfontlist->hfont);
3121 HeapFree(GetProcessHeap(), 0, hfontlist);
3122 free_font(child->font);
3124 HeapFree(GetProcessHeap(), 0, child);
3127 if (font->ft_face) pFT_Done_Face(font->ft_face);
3128 if (font->mapping) unmap_font_file( font->mapping );
3129 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3130 HeapFree(GetProcessHeap(), 0, font->potm);
3131 HeapFree(GetProcessHeap(), 0, font->name);
3132 for (i = 0; i < font->gmsize; i++)
3133 HeapFree(GetProcessHeap(),0,font->gm[i]);
3134 HeapFree(GetProcessHeap(), 0, font->gm);
3135 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3136 HeapFree(GetProcessHeap(), 0, font);
3140 /*************************************************************
3141 * load_VDMX
3143 * load the vdmx entry for the specified height
3146 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3147 ( ( (FT_ULong)_x4 << 24 ) | \
3148 ( (FT_ULong)_x3 << 16 ) | \
3149 ( (FT_ULong)_x2 << 8 ) | \
3150 (FT_ULong)_x1 )
3152 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3154 typedef struct {
3155 BYTE bCharSet;
3156 BYTE xRatio;
3157 BYTE yStartRatio;
3158 BYTE yEndRatio;
3159 } Ratios;
3161 typedef struct {
3162 WORD recs;
3163 BYTE startsz;
3164 BYTE endsz;
3165 } VDMX_group;
3167 static LONG load_VDMX(GdiFont *font, LONG height)
3169 WORD hdr[3], tmp;
3170 VDMX_group group;
3171 BYTE devXRatio, devYRatio;
3172 USHORT numRecs, numRatios;
3173 DWORD result, offset = -1;
3174 LONG ppem = 0;
3175 int i;
3177 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3179 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3180 return ppem;
3182 /* FIXME: need the real device aspect ratio */
3183 devXRatio = 1;
3184 devYRatio = 1;
3186 numRecs = GET_BE_WORD(hdr[1]);
3187 numRatios = GET_BE_WORD(hdr[2]);
3189 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3190 for(i = 0; i < numRatios; i++) {
3191 Ratios ratio;
3193 offset = (3 * 2) + (i * sizeof(Ratios));
3194 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3195 offset = -1;
3197 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3199 if((ratio.xRatio == 0 &&
3200 ratio.yStartRatio == 0 &&
3201 ratio.yEndRatio == 0) ||
3202 (devXRatio == ratio.xRatio &&
3203 devYRatio >= ratio.yStartRatio &&
3204 devYRatio <= ratio.yEndRatio))
3206 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3207 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3208 offset = GET_BE_WORD(tmp);
3209 break;
3213 if(offset == -1) {
3214 FIXME("No suitable ratio found\n");
3215 return ppem;
3218 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3219 USHORT recs;
3220 BYTE startsz, endsz;
3221 WORD *vTable;
3223 recs = GET_BE_WORD(group.recs);
3224 startsz = group.startsz;
3225 endsz = group.endsz;
3227 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3229 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3230 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3231 if(result == GDI_ERROR) {
3232 FIXME("Failed to retrieve vTable\n");
3233 goto end;
3236 if(height > 0) {
3237 for(i = 0; i < recs; i++) {
3238 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3239 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3240 ppem = GET_BE_WORD(vTable[i * 3]);
3242 if(yMax + -yMin == height) {
3243 font->yMax = yMax;
3244 font->yMin = yMin;
3245 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3246 break;
3248 if(yMax + -yMin > height) {
3249 if(--i < 0) {
3250 ppem = 0;
3251 goto end; /* failed */
3253 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3254 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3255 ppem = GET_BE_WORD(vTable[i * 3]);
3256 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3257 break;
3260 if(!font->yMax) {
3261 ppem = 0;
3262 TRACE("ppem not found for height %d\n", height);
3265 end:
3266 HeapFree(GetProcessHeap(), 0, vTable);
3269 return ppem;
3272 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3274 if(font->font_desc.hash != fd->hash) return TRUE;
3275 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3276 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3277 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3278 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3281 static void calc_hash(FONT_DESC *pfd)
3283 DWORD hash = 0, *ptr, two_chars;
3284 WORD *pwc;
3285 unsigned int i;
3287 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3288 hash ^= *ptr;
3289 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3290 hash ^= *ptr;
3291 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3292 two_chars = *ptr;
3293 pwc = (WCHAR *)&two_chars;
3294 if(!*pwc) break;
3295 *pwc = toupperW(*pwc);
3296 pwc++;
3297 *pwc = toupperW(*pwc);
3298 hash ^= two_chars;
3299 if(!*pwc) break;
3301 hash ^= !pfd->can_use_bitmap;
3302 pfd->hash = hash;
3303 return;
3306 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3308 GdiFont *ret;
3309 FONT_DESC fd;
3310 HFONTLIST *hflist;
3311 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3313 fd.lf = *plf;
3314 fd.matrix = *pmat;
3315 fd.can_use_bitmap = can_use_bitmap;
3316 calc_hash(&fd);
3318 /* try the child list */
3319 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3320 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3321 if(!fontcmp(ret, &fd)) {
3322 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3323 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3324 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3325 if(hflist->hfont == hfont)
3326 return ret;
3331 /* try the in-use list */
3332 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3333 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3334 if(!fontcmp(ret, &fd)) {
3335 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3336 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3337 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3338 if(hflist->hfont == hfont)
3339 return ret;
3341 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3342 hflist->hfont = hfont;
3343 list_add_head(&ret->hfontlist, &hflist->entry);
3344 return ret;
3348 /* then the unused list */
3349 font_elem_ptr = list_head(&unused_gdi_font_list);
3350 while(font_elem_ptr) {
3351 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3352 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3353 if(!fontcmp(ret, &fd)) {
3354 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3355 assert(list_empty(&ret->hfontlist));
3356 TRACE("Found %p in unused list\n", ret);
3357 list_remove(&ret->entry);
3358 list_add_head(&gdi_font_list, &ret->entry);
3359 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3360 hflist->hfont = hfont;
3361 list_add_head(&ret->hfontlist, &hflist->entry);
3362 return ret;
3365 return NULL;
3368 static void add_to_cache(GdiFont *font)
3370 static DWORD cache_num = 1;
3372 font->cache_num = cache_num++;
3373 list_add_head(&gdi_font_list, &font->entry);
3376 /*************************************************************
3377 * create_child_font_list
3379 static BOOL create_child_font_list(GdiFont *font)
3381 BOOL ret = FALSE;
3382 SYSTEM_LINKS *font_link;
3383 CHILD_FONT *font_link_entry, *new_child;
3384 FontSubst *psub;
3385 WCHAR* font_name;
3387 psub = get_font_subst(&font_subst_list, font->name, -1);
3388 font_name = psub ? psub->to.name : font->name;
3389 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3391 if(!strcmpiW(font_link->font_name, font_name))
3393 TRACE("found entry in system list\n");
3394 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3396 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3397 new_child->face = font_link_entry->face;
3398 new_child->font = NULL;
3399 list_add_tail(&font->child_fonts, &new_child->entry);
3400 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3402 ret = TRUE;
3403 break;
3407 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3408 * Sans Serif. This is how asian windows get default fallbacks for fonts
3410 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3411 font->charset != OEM_CHARSET &&
3412 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3413 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3415 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3417 TRACE("found entry in default fallback list\n");
3418 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3420 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3421 new_child->face = font_link_entry->face;
3422 new_child->font = NULL;
3423 list_add_tail(&font->child_fonts, &new_child->entry);
3424 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3426 ret = TRUE;
3427 break;
3431 return ret;
3434 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3436 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3438 if (pFT_Set_Charmap)
3440 FT_Int i;
3441 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3443 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3445 for (i = 0; i < ft_face->num_charmaps; i++)
3447 if (ft_face->charmaps[i]->encoding == encoding)
3449 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3450 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3452 switch (ft_face->charmaps[i]->platform_id)
3454 default:
3455 cmap_def = ft_face->charmaps[i];
3456 break;
3457 case 0: /* Apple Unicode */
3458 cmap0 = ft_face->charmaps[i];
3459 break;
3460 case 1: /* Macintosh */
3461 cmap1 = ft_face->charmaps[i];
3462 break;
3463 case 2: /* ISO */
3464 cmap2 = ft_face->charmaps[i];
3465 break;
3466 case 3: /* Microsoft */
3467 cmap3 = ft_face->charmaps[i];
3468 break;
3472 if (cmap3) /* prefer Microsoft cmap table */
3473 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3474 else if (cmap1)
3475 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3476 else if (cmap2)
3477 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3478 else if (cmap0)
3479 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3480 else if (cmap_def)
3481 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3483 return ft_err == FT_Err_Ok;
3486 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3489 /*************************************************************
3490 * WineEngCreateFontInstance
3493 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3495 GdiFont *ret;
3496 Face *face, *best, *best_bitmap;
3497 Family *family, *last_resort_family;
3498 struct list *family_elem_ptr, *face_elem_ptr;
3499 INT height, width = 0;
3500 unsigned int score = 0, new_score;
3501 signed int diff = 0, newdiff;
3502 BOOL bd, it, can_use_bitmap;
3503 LOGFONTW lf;
3504 CHARSETINFO csi;
3505 HFONTLIST *hflist;
3506 FMAT2 dcmat;
3507 FontSubst *psub = NULL;
3509 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3510 lf.lfWidth = abs(lf.lfWidth);
3512 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3514 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3515 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3516 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3517 lf.lfEscapement);
3519 if(dc->GraphicsMode == GM_ADVANCED)
3520 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3521 else
3523 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3524 font scaling abilities. */
3525 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3526 dcmat.eM21 = dcmat.eM12 = 0;
3529 /* Try to avoid not necessary glyph transformations */
3530 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3532 lf.lfHeight *= fabs(dcmat.eM11);
3533 lf.lfWidth *= fabs(dcmat.eM11);
3534 dcmat.eM11 = dcmat.eM22 = 1.0;
3537 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3538 dcmat.eM21, dcmat.eM22);
3540 GDI_CheckNotLock();
3541 EnterCriticalSection( &freetype_cs );
3543 /* check the cache first */
3544 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3545 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3546 LeaveCriticalSection( &freetype_cs );
3547 return ret;
3550 TRACE("not in cache\n");
3551 if(list_empty(&font_list)) /* No fonts installed */
3553 TRACE("No fonts installed\n");
3554 LeaveCriticalSection( &freetype_cs );
3555 return NULL;
3557 if(!have_installed_roman_font)
3559 TRACE("No roman font installed\n");
3560 LeaveCriticalSection( &freetype_cs );
3561 return NULL;
3564 ret = alloc_font();
3566 ret->font_desc.matrix = dcmat;
3567 ret->font_desc.lf = lf;
3568 ret->font_desc.can_use_bitmap = can_use_bitmap;
3569 calc_hash(&ret->font_desc);
3570 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3571 hflist->hfont = hfont;
3572 list_add_head(&ret->hfontlist, &hflist->entry);
3574 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3575 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3576 original value lfCharSet. Note this is a special case for
3577 Symbol and doesn't happen at least for "Wingdings*" */
3579 if(!strcmpiW(lf.lfFaceName, SymbolW))
3580 lf.lfCharSet = SYMBOL_CHARSET;
3582 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3583 switch(lf.lfCharSet) {
3584 case DEFAULT_CHARSET:
3585 csi.fs.fsCsb[0] = 0;
3586 break;
3587 default:
3588 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3589 csi.fs.fsCsb[0] = 0;
3590 break;
3594 family = NULL;
3595 if(lf.lfFaceName[0] != '\0') {
3596 SYSTEM_LINKS *font_link;
3597 CHILD_FONT *font_link_entry;
3598 LPWSTR FaceName = lf.lfFaceName;
3601 * Check for a leading '@' this signals that the font is being
3602 * requested in tategaki mode (vertical writing substitution) but
3603 * does not affect the fontface that is to be selected.
3605 if (lf.lfFaceName[0]=='@')
3606 FaceName = &lf.lfFaceName[1];
3608 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3610 if(psub) {
3611 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3612 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3613 if (psub->to.charset != -1)
3614 lf.lfCharSet = psub->to.charset;
3617 /* We want a match on name and charset or just name if
3618 charset was DEFAULT_CHARSET. If the latter then
3619 we fixup the returned charset later in get_nearest_charset
3620 where we'll either use the charset of the current ansi codepage
3621 or if that's unavailable the first charset that the font supports.
3623 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3624 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3625 if (!strcmpiW(family->FamilyName, FaceName) ||
3626 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3628 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3629 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3630 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3631 if(face->scalable || can_use_bitmap)
3632 goto found;
3638 * Try check the SystemLink list first for a replacement font.
3639 * We may find good replacements there.
3641 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3643 if(!strcmpiW(font_link->font_name, FaceName) ||
3644 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3646 TRACE("found entry in system list\n");
3647 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3649 face = font_link_entry->face;
3650 family = face->family;
3651 if(csi.fs.fsCsb[0] &
3652 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3654 if(face->scalable || can_use_bitmap)
3655 goto found;
3662 psub = NULL; /* substitution is no more relevant */
3664 /* If requested charset was DEFAULT_CHARSET then try using charset
3665 corresponding to the current ansi codepage */
3666 if (!csi.fs.fsCsb[0])
3668 INT acp = GetACP();
3669 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3670 FIXME("TCI failed on codepage %d\n", acp);
3671 csi.fs.fsCsb[0] = 0;
3672 } else
3673 lf.lfCharSet = csi.ciCharset;
3676 /* Face families are in the top 4 bits of lfPitchAndFamily,
3677 so mask with 0xF0 before testing */
3679 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3680 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3681 strcpyW(lf.lfFaceName, defFixed);
3682 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3683 strcpyW(lf.lfFaceName, defSerif);
3684 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3685 strcpyW(lf.lfFaceName, defSans);
3686 else
3687 strcpyW(lf.lfFaceName, defSans);
3688 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3689 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3690 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3691 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3692 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3693 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3694 if(face->scalable || can_use_bitmap)
3695 goto found;
3700 last_resort_family = NULL;
3701 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3702 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3703 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3704 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3705 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3706 if(face->scalable)
3707 goto found;
3708 if(can_use_bitmap && !last_resort_family)
3709 last_resort_family = family;
3714 if(last_resort_family) {
3715 family = last_resort_family;
3716 csi.fs.fsCsb[0] = 0;
3717 goto found;
3720 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3721 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3722 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3723 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3724 if(face->scalable) {
3725 csi.fs.fsCsb[0] = 0;
3726 WARN("just using first face for now\n");
3727 goto found;
3729 if(can_use_bitmap && !last_resort_family)
3730 last_resort_family = family;
3733 if(!last_resort_family) {
3734 FIXME("can't find a single appropriate font - bailing\n");
3735 free_font(ret);
3736 LeaveCriticalSection( &freetype_cs );
3737 return NULL;
3740 WARN("could only find a bitmap font - this will probably look awful!\n");
3741 family = last_resort_family;
3742 csi.fs.fsCsb[0] = 0;
3744 found:
3745 it = lf.lfItalic ? 1 : 0;
3746 bd = lf.lfWeight > 550 ? 1 : 0;
3748 height = lf.lfHeight;
3750 face = best = best_bitmap = NULL;
3751 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3753 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3755 BOOL italic, bold;
3757 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3758 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3759 new_score = (italic ^ it) + (bold ^ bd);
3760 if(!best || new_score <= score)
3762 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3763 italic, bold, it, bd);
3764 score = new_score;
3765 best = face;
3766 if(best->scalable && score == 0) break;
3767 if(!best->scalable)
3769 if(height > 0)
3770 newdiff = height - (signed int)(best->size.height);
3771 else
3772 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3773 if(!best_bitmap || new_score < score ||
3774 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3776 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3777 diff = newdiff;
3778 best_bitmap = best;
3779 if(score == 0 && diff == 0) break;
3785 if(best)
3786 face = best->scalable ? best : best_bitmap;
3787 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3788 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3790 ret->fs = face->fs;
3792 if(csi.fs.fsCsb[0]) {
3793 ret->charset = lf.lfCharSet;
3794 ret->codepage = csi.ciACP;
3796 else
3797 ret->charset = get_nearest_charset(face, &ret->codepage);
3799 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3800 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3802 ret->aveWidth = height ? lf.lfWidth : 0;
3804 if(!face->scalable) {
3805 /* Windows uses integer scaling factors for bitmap fonts */
3806 INT scale, scaled_height;
3807 GdiFont *cachedfont;
3809 /* FIXME: rotation of bitmap fonts is ignored */
3810 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3811 if (ret->aveWidth)
3812 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3813 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3814 dcmat.eM11 = dcmat.eM22 = 1.0;
3815 /* As we changed the matrix, we need to search the cache for the font again,
3816 * otherwise we might explode the cache. */
3817 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3818 TRACE("Found cached font after non-scalable matrix rescale!\n");
3819 free_font( ret );
3820 LeaveCriticalSection( &freetype_cs );
3821 return cachedfont;
3823 calc_hash(&ret->font_desc);
3825 if (height != 0) height = diff;
3826 height += face->size.height;
3828 scale = (height + face->size.height - 1) / face->size.height;
3829 scaled_height = scale * face->size.height;
3830 /* Only jump to the next height if the difference <= 25% original height */
3831 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3832 /* The jump between unscaled and doubled is delayed by 1 */
3833 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3834 ret->scale_y = scale;
3836 width = face->size.x_ppem >> 6;
3837 height = face->size.y_ppem >> 6;
3839 else
3840 ret->scale_y = 1.0;
3841 TRACE("font scale y: %f\n", ret->scale_y);
3843 ret->ft_face = OpenFontFace(ret, face, width, height);
3845 if (!ret->ft_face)
3847 free_font( ret );
3848 LeaveCriticalSection( &freetype_cs );
3849 return 0;
3852 ret->ntmFlags = face->ntmFlags;
3854 if (ret->charset == SYMBOL_CHARSET &&
3855 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3856 /* No ops */
3858 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3859 /* No ops */
3861 else {
3862 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3865 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3866 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3867 ret->underline = lf.lfUnderline ? 0xff : 0;
3868 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3869 create_child_font_list(ret);
3871 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3873 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3874 if (length != GDI_ERROR)
3876 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3877 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3878 TRACE("Loaded GSUB table of %i bytes\n",length);
3882 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3884 add_to_cache(ret);
3885 LeaveCriticalSection( &freetype_cs );
3886 return ret;
3889 static void dump_gdi_font_list(void)
3891 GdiFont *gdiFont;
3892 struct list *elem_ptr;
3894 TRACE("---------- gdiFont Cache ----------\n");
3895 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3896 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3897 TRACE("gdiFont=%p %s %d\n",
3898 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3901 TRACE("---------- Unused gdiFont Cache ----------\n");
3902 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3903 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3904 TRACE("gdiFont=%p %s %d\n",
3905 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3909 /*************************************************************
3910 * WineEngDestroyFontInstance
3912 * free the gdiFont associated with this handle
3915 BOOL WineEngDestroyFontInstance(HFONT handle)
3917 GdiFont *gdiFont;
3918 HFONTLIST *hflist;
3919 BOOL ret = FALSE;
3920 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3921 int i = 0;
3923 GDI_CheckNotLock();
3924 EnterCriticalSection( &freetype_cs );
3926 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3928 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3929 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3930 if(hflist->hfont == handle)
3932 TRACE("removing child font %p from child list\n", gdiFont);
3933 list_remove(&gdiFont->entry);
3934 LeaveCriticalSection( &freetype_cs );
3935 return TRUE;
3939 TRACE("destroying hfont=%p\n", handle);
3940 if(TRACE_ON(font))
3941 dump_gdi_font_list();
3943 font_elem_ptr = list_head(&gdi_font_list);
3944 while(font_elem_ptr) {
3945 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3946 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3948 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3949 while(hfontlist_elem_ptr) {
3950 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3951 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3952 if(hflist->hfont == handle) {
3953 list_remove(&hflist->entry);
3954 HeapFree(GetProcessHeap(), 0, hflist);
3955 ret = TRUE;
3958 if(list_empty(&gdiFont->hfontlist)) {
3959 TRACE("Moving to Unused list\n");
3960 list_remove(&gdiFont->entry);
3961 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3966 font_elem_ptr = list_head(&unused_gdi_font_list);
3967 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3968 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3969 while(font_elem_ptr) {
3970 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3971 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3972 TRACE("freeing %p\n", gdiFont);
3973 list_remove(&gdiFont->entry);
3974 free_font(gdiFont);
3976 LeaveCriticalSection( &freetype_cs );
3977 return ret;
3980 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3981 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3983 GdiFont *font;
3984 LONG width, height;
3986 if (face->cached_enum_data)
3988 TRACE("Cached\n");
3989 *pelf = face->cached_enum_data->elf;
3990 *pntm = face->cached_enum_data->ntm;
3991 *ptype = face->cached_enum_data->type;
3992 return;
3995 font = alloc_font();
3997 if(face->scalable) {
3998 height = -2048; /* 2048 is the most common em size */
3999 width = 0;
4000 } else {
4001 height = face->size.y_ppem >> 6;
4002 width = face->size.x_ppem >> 6;
4004 font->scale_y = 1.0;
4006 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4008 free_font(font);
4009 return;
4012 font->name = strdupW(face->family->FamilyName);
4013 font->ntmFlags = face->ntmFlags;
4015 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4017 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4019 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4021 lstrcpynW(pelf->elfLogFont.lfFaceName,
4022 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4023 LF_FACESIZE);
4024 lstrcpynW(pelf->elfFullName,
4025 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4026 LF_FULLFACESIZE);
4027 lstrcpynW(pelf->elfStyle,
4028 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4029 LF_FACESIZE);
4031 else
4033 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4035 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4037 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4038 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4039 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4042 pntm->ntmTm.ntmFlags = face->ntmFlags;
4043 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4044 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4045 pntm->ntmFontSig = face->fs;
4047 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4049 pelf->elfLogFont.lfEscapement = 0;
4050 pelf->elfLogFont.lfOrientation = 0;
4051 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4052 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4053 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4054 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4055 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4056 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4057 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4058 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4059 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4060 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4061 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4063 *ptype = 0;
4064 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4065 *ptype |= TRUETYPE_FONTTYPE;
4066 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4067 *ptype |= DEVICE_FONTTYPE;
4068 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4069 *ptype |= RASTER_FONTTYPE;
4071 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4072 if (face->cached_enum_data)
4074 face->cached_enum_data->elf = *pelf;
4075 face->cached_enum_data->ntm = *pntm;
4076 face->cached_enum_data->type = *ptype;
4079 free_font(font);
4082 /*************************************************************
4083 * WineEngEnumFonts
4086 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4088 Family *family;
4089 Face *face;
4090 struct list *family_elem_ptr, *face_elem_ptr;
4091 ENUMLOGFONTEXW elf;
4092 NEWTEXTMETRICEXW ntm;
4093 DWORD type;
4094 FONTSIGNATURE fs;
4095 CHARSETINFO csi;
4096 LOGFONTW lf;
4097 int i;
4099 if (!plf)
4101 lf.lfCharSet = DEFAULT_CHARSET;
4102 lf.lfPitchAndFamily = 0;
4103 lf.lfFaceName[0] = 0;
4104 plf = &lf;
4107 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4109 GDI_CheckNotLock();
4110 EnterCriticalSection( &freetype_cs );
4111 if(plf->lfFaceName[0]) {
4112 FontSubst *psub;
4113 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4115 if(psub) {
4116 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4117 debugstr_w(psub->to.name));
4118 lf = *plf;
4119 strcpyW(lf.lfFaceName, psub->to.name);
4120 plf = &lf;
4123 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4124 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4125 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
4126 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4127 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4128 GetEnumStructs(face, &elf, &ntm, &type);
4129 for(i = 0; i < 32; i++) {
4130 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4131 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4132 strcpyW(elf.elfScript, OEM_DOSW);
4133 i = 32; /* break out of loop */
4134 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4135 continue;
4136 else {
4137 fs.fsCsb[0] = 1L << i;
4138 fs.fsCsb[1] = 0;
4139 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4140 TCI_SRCFONTSIG))
4141 csi.ciCharset = DEFAULT_CHARSET;
4142 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4143 if(csi.ciCharset != DEFAULT_CHARSET) {
4144 elf.elfLogFont.lfCharSet =
4145 ntm.ntmTm.tmCharSet = csi.ciCharset;
4146 if(ElfScriptsW[i])
4147 strcpyW(elf.elfScript, ElfScriptsW[i]);
4148 else
4149 FIXME("Unknown elfscript for bit %d\n", i);
4152 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4153 debugstr_w(elf.elfLogFont.lfFaceName),
4154 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4155 csi.ciCharset, type, debugstr_w(elf.elfScript),
4156 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4157 ntm.ntmTm.ntmFlags);
4158 /* release section before callback (FIXME) */
4159 LeaveCriticalSection( &freetype_cs );
4160 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4161 EnterCriticalSection( &freetype_cs );
4166 } else {
4167 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4168 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4169 face_elem_ptr = list_head(&family->faces);
4170 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4171 GetEnumStructs(face, &elf, &ntm, &type);
4172 for(i = 0; i < 32; i++) {
4173 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4174 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4175 strcpyW(elf.elfScript, OEM_DOSW);
4176 i = 32; /* break out of loop */
4177 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4178 continue;
4179 else {
4180 fs.fsCsb[0] = 1L << i;
4181 fs.fsCsb[1] = 0;
4182 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4183 TCI_SRCFONTSIG))
4184 csi.ciCharset = DEFAULT_CHARSET;
4185 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4186 if(csi.ciCharset != DEFAULT_CHARSET) {
4187 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4188 csi.ciCharset;
4189 if(ElfScriptsW[i])
4190 strcpyW(elf.elfScript, ElfScriptsW[i]);
4191 else
4192 FIXME("Unknown elfscript for bit %d\n", i);
4195 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4196 debugstr_w(elf.elfLogFont.lfFaceName),
4197 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4198 csi.ciCharset, type, debugstr_w(elf.elfScript),
4199 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4200 ntm.ntmTm.ntmFlags);
4201 /* release section before callback (FIXME) */
4202 LeaveCriticalSection( &freetype_cs );
4203 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4204 EnterCriticalSection( &freetype_cs );
4208 LeaveCriticalSection( &freetype_cs );
4209 return 1;
4212 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4214 pt->x.value = vec->x >> 6;
4215 pt->x.fract = (vec->x & 0x3f) << 10;
4216 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4217 pt->y.value = vec->y >> 6;
4218 pt->y.fract = (vec->y & 0x3f) << 10;
4219 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4220 return;
4223 /***************************************************
4224 * According to the MSDN documentation on WideCharToMultiByte,
4225 * certain codepages cannot set the default_used parameter.
4226 * This returns TRUE if the codepage can set that parameter, false else
4227 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4229 static BOOL codepage_sets_default_used(UINT codepage)
4231 switch (codepage)
4233 case CP_UTF7:
4234 case CP_UTF8:
4235 case CP_SYMBOL:
4236 return FALSE;
4237 default:
4238 return TRUE;
4243 * GSUB Table handling functions
4246 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4248 const GSUB_CoverageFormat1* cf1;
4250 cf1 = table;
4252 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4254 int count = GET_BE_WORD(cf1->GlyphCount);
4255 int i;
4256 TRACE("Coverage Format 1, %i glyphs\n",count);
4257 for (i = 0; i < count; i++)
4258 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4259 return i;
4260 return -1;
4262 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4264 const GSUB_CoverageFormat2* cf2;
4265 int i;
4266 int count;
4267 cf2 = (const GSUB_CoverageFormat2*)cf1;
4269 count = GET_BE_WORD(cf2->RangeCount);
4270 TRACE("Coverage Format 2, %i ranges\n",count);
4271 for (i = 0; i < count; i++)
4273 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4274 return -1;
4275 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4276 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4278 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4279 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4282 return -1;
4284 else
4285 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4287 return -1;
4290 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4292 const GSUB_ScriptList *script;
4293 const GSUB_Script *deflt = NULL;
4294 int i;
4295 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4297 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4298 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4300 const GSUB_Script *scr;
4301 int offset;
4303 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4304 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4306 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4307 return scr;
4308 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4309 deflt = scr;
4311 return deflt;
4314 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4316 int i;
4317 int offset;
4318 const GSUB_LangSys *Lang;
4320 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4322 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4324 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4325 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4327 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4328 return Lang;
4330 offset = GET_BE_WORD(script->DefaultLangSys);
4331 if (offset)
4333 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4334 return Lang;
4336 return NULL;
4339 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4341 int i;
4342 const GSUB_FeatureList *feature;
4343 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4345 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4346 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4348 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4349 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4351 const GSUB_Feature *feat;
4352 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4353 return feat;
4356 return NULL;
4359 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4361 int i;
4362 int offset;
4363 const GSUB_LookupList *lookup;
4364 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4366 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4367 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4369 const GSUB_LookupTable *look;
4370 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4371 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4372 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4373 if (GET_BE_WORD(look->LookupType) != 1)
4374 FIXME("We only handle SubType 1\n");
4375 else
4377 int j;
4379 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4381 const GSUB_SingleSubstFormat1 *ssf1;
4382 offset = GET_BE_WORD(look->SubTable[j]);
4383 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4384 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4386 int offset = GET_BE_WORD(ssf1->Coverage);
4387 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4388 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4390 TRACE(" Glyph 0x%x ->",glyph);
4391 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4392 TRACE(" 0x%x\n",glyph);
4395 else
4397 const GSUB_SingleSubstFormat2 *ssf2;
4398 INT index;
4399 INT offset;
4401 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4402 offset = GET_BE_WORD(ssf1->Coverage);
4403 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4404 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4405 TRACE(" Coverage index %i\n",index);
4406 if (index != -1)
4408 TRACE(" Glyph is 0x%x ->",glyph);
4409 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4410 TRACE("0x%x\n",glyph);
4416 return glyph;
4419 static const char* get_opentype_script(const GdiFont *font)
4422 * I am not sure if this is the correct way to generate our script tag
4425 switch (font->charset)
4427 case ANSI_CHARSET: return "latn";
4428 case BALTIC_CHARSET: return "latn"; /* ?? */
4429 case CHINESEBIG5_CHARSET: return "hani";
4430 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4431 case GB2312_CHARSET: return "hani";
4432 case GREEK_CHARSET: return "grek";
4433 case HANGUL_CHARSET: return "hang";
4434 case RUSSIAN_CHARSET: return "cyrl";
4435 case SHIFTJIS_CHARSET: return "kana";
4436 case TURKISH_CHARSET: return "latn"; /* ?? */
4437 case VIETNAMESE_CHARSET: return "latn";
4438 case JOHAB_CHARSET: return "latn"; /* ?? */
4439 case ARABIC_CHARSET: return "arab";
4440 case HEBREW_CHARSET: return "hebr";
4441 case THAI_CHARSET: return "thai";
4442 default: return "latn";
4446 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4448 const GSUB_Header *header;
4449 const GSUB_Script *script;
4450 const GSUB_LangSys *language;
4451 const GSUB_Feature *feature;
4453 if (!font->GSUB_Table)
4454 return glyph;
4456 header = font->GSUB_Table;
4458 script = GSUB_get_script_table(header, get_opentype_script(font));
4459 if (!script)
4461 TRACE("Script not found\n");
4462 return glyph;
4464 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4465 if (!language)
4467 TRACE("Language not found\n");
4468 return glyph;
4470 feature = GSUB_get_feature(header, language, "vrt2");
4471 if (!feature)
4472 feature = GSUB_get_feature(header, language, "vert");
4473 if (!feature)
4475 TRACE("vrt2/vert feature not found\n");
4476 return glyph;
4478 return GSUB_apply_feature(header, feature, glyph);
4481 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4483 FT_UInt glyphId;
4485 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4486 WCHAR wc = (WCHAR)glyph;
4487 BOOL default_used;
4488 BOOL *default_used_pointer;
4489 FT_UInt ret;
4490 char buf;
4491 default_used_pointer = NULL;
4492 default_used = FALSE;
4493 if (codepage_sets_default_used(font->codepage))
4494 default_used_pointer = &default_used;
4495 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4496 ret = 0;
4497 else
4498 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4499 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4500 return get_GSUB_vert_glyph(font,ret);
4503 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4504 glyph = glyph + 0xf000;
4505 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4506 return get_GSUB_vert_glyph(font,glyphId);
4509 /*************************************************************
4510 * WineEngGetGlyphIndices
4513 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4514 LPWORD pgi, DWORD flags)
4516 int i;
4517 int default_char = -1;
4519 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4521 for(i = 0; i < count; i++)
4523 pgi[i] = get_glyph_index(font, lpstr[i]);
4524 if (pgi[i] == 0)
4526 if (default_char == -1)
4528 if (FT_IS_SFNT(font->ft_face))
4530 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4531 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4533 else
4535 TEXTMETRICW textm;
4536 WineEngGetTextMetrics(font, &textm);
4537 default_char = textm.tmDefaultChar;
4540 pgi[i] = default_char;
4543 return count;
4546 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4548 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4549 return !memcmp(matrix, &identity, sizeof(FMAT2));
4552 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4554 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4555 return !memcmp(matrix, &identity, sizeof(MAT2));
4558 /*************************************************************
4559 * WineEngGetGlyphOutline
4561 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4562 * except that the first parameter is the HWINEENGFONT of the font in
4563 * question rather than an HDC.
4566 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4567 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4568 const MAT2* lpmat)
4570 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4571 FT_Face ft_face = incoming_font->ft_face;
4572 GdiFont *font = incoming_font;
4573 FT_UInt glyph_index;
4574 DWORD width, height, pitch, needed = 0;
4575 FT_Bitmap ft_bitmap;
4576 FT_Error err;
4577 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4578 FT_Angle angle = 0;
4579 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4580 double widthRatio = 1.0;
4581 FT_Matrix transMat = identityMat;
4582 FT_Matrix transMatUnrotated;
4583 BOOL needsTransform = FALSE;
4584 BOOL tategaki = (font->GSUB_Table != NULL);
4585 UINT original_index;
4587 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4588 buflen, buf, lpmat);
4590 TRACE("font transform %f %f %f %f\n",
4591 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4592 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4594 GDI_CheckNotLock();
4595 EnterCriticalSection( &freetype_cs );
4597 if(format & GGO_GLYPH_INDEX) {
4598 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4599 original_index = glyph;
4600 format &= ~GGO_GLYPH_INDEX;
4601 } else {
4602 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4603 ft_face = font->ft_face;
4604 original_index = glyph_index;
4607 if(format & GGO_UNHINTED) {
4608 load_flags |= FT_LOAD_NO_HINTING;
4609 format &= ~GGO_UNHINTED;
4612 /* tategaki never appears to happen to lower glyph index */
4613 if (glyph_index < TATEGAKI_LOWER_BOUND )
4614 tategaki = FALSE;
4616 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4617 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4618 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4619 font->gmsize * sizeof(GM*));
4620 } else {
4621 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4622 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4624 *lpgm = FONT_GM(font,original_index)->gm;
4625 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4626 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4627 lpgm->gmCellIncX, lpgm->gmCellIncY);
4628 LeaveCriticalSection( &freetype_cs );
4629 return 1; /* FIXME */
4633 if (!font->gm[original_index / GM_BLOCK_SIZE])
4634 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4636 /* Scaling factor */
4637 if (font->aveWidth)
4639 TEXTMETRICW tm;
4641 WineEngGetTextMetrics(font, &tm);
4643 widthRatio = (double)font->aveWidth;
4644 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4646 else
4647 widthRatio = font->scale_y;
4649 /* Scaling transform */
4650 if (widthRatio != 1.0 || font->scale_y != 1.0)
4652 FT_Matrix scaleMat;
4653 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4654 scaleMat.xy = 0;
4655 scaleMat.yx = 0;
4656 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4658 pFT_Matrix_Multiply(&scaleMat, &transMat);
4659 needsTransform = TRUE;
4662 /* Slant transform */
4663 if (font->fake_italic) {
4664 FT_Matrix slantMat;
4666 slantMat.xx = (1 << 16);
4667 slantMat.xy = ((1 << 16) >> 2);
4668 slantMat.yx = 0;
4669 slantMat.yy = (1 << 16);
4670 pFT_Matrix_Multiply(&slantMat, &transMat);
4671 needsTransform = TRUE;
4674 /* Rotation transform */
4675 transMatUnrotated = transMat;
4676 if(font->orientation && !tategaki) {
4677 FT_Matrix rotationMat;
4678 FT_Vector vecAngle;
4679 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4680 pFT_Vector_Unit(&vecAngle, angle);
4681 rotationMat.xx = vecAngle.x;
4682 rotationMat.xy = -vecAngle.y;
4683 rotationMat.yx = -rotationMat.xy;
4684 rotationMat.yy = rotationMat.xx;
4686 pFT_Matrix_Multiply(&rotationMat, &transMat);
4687 needsTransform = TRUE;
4690 /* World transform */
4691 if (!is_identity_FMAT2(&font->font_desc.matrix))
4693 FT_Matrix worldMat;
4694 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4695 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4696 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4697 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4698 pFT_Matrix_Multiply(&worldMat, &transMat);
4699 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4700 needsTransform = TRUE;
4703 /* Extra transformation specified by caller */
4704 if (!is_identity_MAT2(lpmat))
4706 FT_Matrix extraMat;
4707 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4708 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4709 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4710 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4711 pFT_Matrix_Multiply(&extraMat, &transMat);
4712 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4713 needsTransform = TRUE;
4716 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4717 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4718 format == GGO_GRAY8_BITMAP))
4720 load_flags |= FT_LOAD_NO_BITMAP;
4723 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4725 if(err) {
4726 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4727 LeaveCriticalSection( &freetype_cs );
4728 return GDI_ERROR;
4731 if(!needsTransform) {
4732 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4733 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4734 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4736 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4737 bottom = (ft_face->glyph->metrics.horiBearingY -
4738 ft_face->glyph->metrics.height) & -64;
4739 lpgm->gmCellIncX = adv;
4740 lpgm->gmCellIncY = 0;
4741 } else {
4742 INT xc, yc;
4743 FT_Vector vec;
4745 left = right = 0;
4747 for(xc = 0; xc < 2; xc++) {
4748 for(yc = 0; yc < 2; yc++) {
4749 vec.x = (ft_face->glyph->metrics.horiBearingX +
4750 xc * ft_face->glyph->metrics.width);
4751 vec.y = ft_face->glyph->metrics.horiBearingY -
4752 yc * ft_face->glyph->metrics.height;
4753 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4754 pFT_Vector_Transform(&vec, &transMat);
4755 if(xc == 0 && yc == 0) {
4756 left = right = vec.x;
4757 top = bottom = vec.y;
4758 } else {
4759 if(vec.x < left) left = vec.x;
4760 else if(vec.x > right) right = vec.x;
4761 if(vec.y < bottom) bottom = vec.y;
4762 else if(vec.y > top) top = vec.y;
4766 left = left & -64;
4767 right = (right + 63) & -64;
4768 bottom = bottom & -64;
4769 top = (top + 63) & -64;
4771 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4772 vec.x = ft_face->glyph->metrics.horiAdvance;
4773 vec.y = 0;
4774 pFT_Vector_Transform(&vec, &transMat);
4775 lpgm->gmCellIncX = (vec.x+63) >> 6;
4776 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4778 vec.x = ft_face->glyph->metrics.horiAdvance;
4779 vec.y = 0;
4780 pFT_Vector_Transform(&vec, &transMatUnrotated);
4781 adv = (vec.x+63) >> 6;
4784 lsb = left >> 6;
4785 bbx = (right - left) >> 6;
4786 lpgm->gmBlackBoxX = (right - left) >> 6;
4787 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4788 lpgm->gmptGlyphOrigin.x = left >> 6;
4789 lpgm->gmptGlyphOrigin.y = top >> 6;
4791 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4792 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4793 lpgm->gmCellIncX, lpgm->gmCellIncY);
4795 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4796 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4798 FONT_GM(font,original_index)->gm = *lpgm;
4799 FONT_GM(font,original_index)->adv = adv;
4800 FONT_GM(font,original_index)->lsb = lsb;
4801 FONT_GM(font,original_index)->bbx = bbx;
4802 FONT_GM(font,original_index)->init = TRUE;
4805 if(format == GGO_METRICS)
4807 LeaveCriticalSection( &freetype_cs );
4808 return 1; /* FIXME */
4811 if(ft_face->glyph->format != ft_glyph_format_outline &&
4812 (format == GGO_NATIVE || format == GGO_BEZIER ||
4813 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4814 format == GGO_GRAY8_BITMAP))
4816 TRACE("loaded a bitmap\n");
4817 LeaveCriticalSection( &freetype_cs );
4818 return GDI_ERROR;
4821 switch(format) {
4822 case GGO_BITMAP:
4823 width = lpgm->gmBlackBoxX;
4824 height = lpgm->gmBlackBoxY;
4825 pitch = ((width + 31) >> 5) << 2;
4826 needed = pitch * height;
4828 if(!buf || !buflen) break;
4830 switch(ft_face->glyph->format) {
4831 case ft_glyph_format_bitmap:
4833 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4834 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4835 INT h = ft_face->glyph->bitmap.rows;
4836 while(h--) {
4837 memcpy(dst, src, w);
4838 src += ft_face->glyph->bitmap.pitch;
4839 dst += pitch;
4841 break;
4844 case ft_glyph_format_outline:
4845 ft_bitmap.width = width;
4846 ft_bitmap.rows = height;
4847 ft_bitmap.pitch = pitch;
4848 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4849 ft_bitmap.buffer = buf;
4851 if(needsTransform)
4852 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4854 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4856 /* Note: FreeType will only set 'black' bits for us. */
4857 memset(buf, 0, needed);
4858 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4859 break;
4861 default:
4862 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4863 LeaveCriticalSection( &freetype_cs );
4864 return GDI_ERROR;
4866 break;
4868 case GGO_GRAY2_BITMAP:
4869 case GGO_GRAY4_BITMAP:
4870 case GGO_GRAY8_BITMAP:
4871 case WINE_GGO_GRAY16_BITMAP:
4873 unsigned int mult, row, col;
4874 BYTE *start, *ptr;
4876 width = lpgm->gmBlackBoxX;
4877 height = lpgm->gmBlackBoxY;
4878 pitch = (width + 3) / 4 * 4;
4879 needed = pitch * height;
4881 if(!buf || !buflen) break;
4883 switch(ft_face->glyph->format) {
4884 case ft_glyph_format_bitmap:
4886 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4887 INT h = ft_face->glyph->bitmap.rows;
4888 INT x;
4889 while(h--) {
4890 for(x = 0; x < pitch; x++)
4892 if(x < ft_face->glyph->bitmap.width)
4893 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4894 else
4895 dst[x] = 0;
4897 src += ft_face->glyph->bitmap.pitch;
4898 dst += pitch;
4900 LeaveCriticalSection( &freetype_cs );
4901 return needed;
4903 case ft_glyph_format_outline:
4905 ft_bitmap.width = width;
4906 ft_bitmap.rows = height;
4907 ft_bitmap.pitch = pitch;
4908 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4909 ft_bitmap.buffer = buf;
4911 if(needsTransform)
4912 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4914 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4916 memset(ft_bitmap.buffer, 0, buflen);
4918 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4920 if(format == GGO_GRAY2_BITMAP)
4921 mult = 4;
4922 else if(format == GGO_GRAY4_BITMAP)
4923 mult = 16;
4924 else if(format == GGO_GRAY8_BITMAP)
4925 mult = 64;
4926 else /* format == WINE_GGO_GRAY16_BITMAP */
4928 LeaveCriticalSection( &freetype_cs );
4929 return needed;
4931 break;
4933 default:
4934 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4935 LeaveCriticalSection( &freetype_cs );
4936 return GDI_ERROR;
4939 start = buf;
4940 for(row = 0; row < height; row++) {
4941 ptr = start;
4942 for(col = 0; col < width; col++, ptr++) {
4943 *ptr = (((int)*ptr) * mult + 128) / 256;
4945 start += pitch;
4947 break;
4950 case WINE_GGO_HRGB_BITMAP:
4951 case WINE_GGO_HBGR_BITMAP:
4952 case WINE_GGO_VRGB_BITMAP:
4953 case WINE_GGO_VBGR_BITMAP:
4954 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4956 switch (ft_face->glyph->format)
4958 case FT_GLYPH_FORMAT_BITMAP:
4960 BYTE *src, *dst;
4961 INT src_pitch, x;
4963 width = lpgm->gmBlackBoxX;
4964 height = lpgm->gmBlackBoxY;
4965 pitch = width * 4;
4966 needed = pitch * height;
4968 if (!buf || !buflen) break;
4970 memset(buf, 0, buflen);
4971 dst = buf;
4972 src = ft_face->glyph->bitmap.buffer;
4973 src_pitch = ft_face->glyph->bitmap.pitch;
4975 while ( height-- )
4977 for (x = 0; x < width; x++)
4979 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4980 ((unsigned int *)dst)[x] = ~0u;
4982 src += src_pitch;
4983 dst += pitch;
4986 break;
4989 case FT_GLYPH_FORMAT_OUTLINE:
4991 unsigned int *dst;
4992 BYTE *src;
4993 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4994 INT x_shift, y_shift;
4995 BOOL rgb;
4996 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4997 FT_Render_Mode render_mode =
4998 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4999 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5001 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5003 if ( render_mode == FT_RENDER_MODE_LCD)
5005 lpgm->gmBlackBoxX += 2;
5006 lpgm->gmptGlyphOrigin.x -= 1;
5008 else
5010 lpgm->gmBlackBoxY += 2;
5011 lpgm->gmptGlyphOrigin.y += 1;
5015 width = lpgm->gmBlackBoxX;
5016 height = lpgm->gmBlackBoxY;
5017 pitch = width * 4;
5018 needed = pitch * height;
5020 if (!buf || !buflen) break;
5022 memset(buf, 0, buflen);
5023 dst = buf;
5024 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5026 if ( needsTransform )
5027 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5029 if ( pFT_Library_SetLcdFilter )
5030 pFT_Library_SetLcdFilter( library, lcdfilter );
5031 pFT_Render_Glyph (ft_face->glyph, render_mode);
5033 src = ft_face->glyph->bitmap.buffer;
5034 src_pitch = ft_face->glyph->bitmap.pitch;
5035 src_width = ft_face->glyph->bitmap.width;
5036 src_height = ft_face->glyph->bitmap.rows;
5038 if ( render_mode == FT_RENDER_MODE_LCD)
5040 rgb_interval = 1;
5041 hmul = 3;
5042 vmul = 1;
5044 else
5046 rgb_interval = src_pitch;
5047 hmul = 1;
5048 vmul = 3;
5051 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5052 if ( x_shift < 0 ) x_shift = 0;
5053 if ( x_shift + (src_width / hmul) > width )
5054 x_shift = width - (src_width / hmul);
5056 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5057 if ( y_shift < 0 ) y_shift = 0;
5058 if ( y_shift + (src_height / vmul) > height )
5059 y_shift = height - (src_height / vmul);
5061 dst += x_shift + y_shift * ( pitch / 4 );
5062 while ( src_height )
5064 for ( x = 0; x < src_width / hmul; x++ )
5066 if ( rgb )
5068 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5069 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5070 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5071 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5073 else
5075 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5076 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5077 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5078 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5081 src += src_pitch * vmul;
5082 dst += pitch / 4;
5083 src_height -= vmul;
5086 break;
5089 default:
5090 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5091 LeaveCriticalSection ( &freetype_cs );
5092 return GDI_ERROR;
5095 break;
5097 #else
5098 LeaveCriticalSection( &freetype_cs );
5099 return GDI_ERROR;
5100 #endif
5102 case GGO_NATIVE:
5104 int contour, point = 0, first_pt;
5105 FT_Outline *outline = &ft_face->glyph->outline;
5106 TTPOLYGONHEADER *pph;
5107 TTPOLYCURVE *ppc;
5108 DWORD pph_start, cpfx, type;
5110 if(buflen == 0) buf = NULL;
5112 if (needsTransform && buf) {
5113 pFT_Outline_Transform(outline, &transMat);
5116 for(contour = 0; contour < outline->n_contours; contour++) {
5117 pph_start = needed;
5118 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5119 first_pt = point;
5120 if(buf) {
5121 pph->dwType = TT_POLYGON_TYPE;
5122 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5124 needed += sizeof(*pph);
5125 point++;
5126 while(point <= outline->contours[contour]) {
5127 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5128 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5129 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5130 cpfx = 0;
5131 do {
5132 if(buf)
5133 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5134 cpfx++;
5135 point++;
5136 } while(point <= outline->contours[contour] &&
5137 (outline->tags[point] & FT_Curve_Tag_On) ==
5138 (outline->tags[point-1] & FT_Curve_Tag_On));
5139 /* At the end of a contour Windows adds the start point, but
5140 only for Beziers */
5141 if(point > outline->contours[contour] &&
5142 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5143 if(buf)
5144 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5145 cpfx++;
5146 } else if(point <= outline->contours[contour] &&
5147 outline->tags[point] & FT_Curve_Tag_On) {
5148 /* add closing pt for bezier */
5149 if(buf)
5150 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5151 cpfx++;
5152 point++;
5154 if(buf) {
5155 ppc->wType = type;
5156 ppc->cpfx = cpfx;
5158 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5160 if(buf)
5161 pph->cb = needed - pph_start;
5163 break;
5165 case GGO_BEZIER:
5167 /* Convert the quadratic Beziers to cubic Beziers.
5168 The parametric eqn for a cubic Bezier is, from PLRM:
5169 r(t) = at^3 + bt^2 + ct + r0
5170 with the control points:
5171 r1 = r0 + c/3
5172 r2 = r1 + (c + b)/3
5173 r3 = r0 + c + b + a
5175 A quadratic Beizer has the form:
5176 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5178 So equating powers of t leads to:
5179 r1 = 2/3 p1 + 1/3 p0
5180 r2 = 2/3 p1 + 1/3 p2
5181 and of course r0 = p0, r3 = p2
5184 int contour, point = 0, first_pt;
5185 FT_Outline *outline = &ft_face->glyph->outline;
5186 TTPOLYGONHEADER *pph;
5187 TTPOLYCURVE *ppc;
5188 DWORD pph_start, cpfx, type;
5189 FT_Vector cubic_control[4];
5190 if(buflen == 0) buf = NULL;
5192 if (needsTransform && buf) {
5193 pFT_Outline_Transform(outline, &transMat);
5196 for(contour = 0; contour < outline->n_contours; contour++) {
5197 pph_start = needed;
5198 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5199 first_pt = point;
5200 if(buf) {
5201 pph->dwType = TT_POLYGON_TYPE;
5202 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5204 needed += sizeof(*pph);
5205 point++;
5206 while(point <= outline->contours[contour]) {
5207 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5208 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5209 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5210 cpfx = 0;
5211 do {
5212 if(type == TT_PRIM_LINE) {
5213 if(buf)
5214 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5215 cpfx++;
5216 point++;
5217 } else {
5218 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5219 so cpfx = 3n */
5221 /* FIXME: Possible optimization in endpoint calculation
5222 if there are two consecutive curves */
5223 cubic_control[0] = outline->points[point-1];
5224 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5225 cubic_control[0].x += outline->points[point].x + 1;
5226 cubic_control[0].y += outline->points[point].y + 1;
5227 cubic_control[0].x >>= 1;
5228 cubic_control[0].y >>= 1;
5230 if(point+1 > outline->contours[contour])
5231 cubic_control[3] = outline->points[first_pt];
5232 else {
5233 cubic_control[3] = outline->points[point+1];
5234 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5235 cubic_control[3].x += outline->points[point].x + 1;
5236 cubic_control[3].y += outline->points[point].y + 1;
5237 cubic_control[3].x >>= 1;
5238 cubic_control[3].y >>= 1;
5241 /* r1 = 1/3 p0 + 2/3 p1
5242 r2 = 1/3 p2 + 2/3 p1 */
5243 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5244 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5245 cubic_control[2] = cubic_control[1];
5246 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5247 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5248 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5249 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5250 if(buf) {
5251 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5252 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5253 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5255 cpfx += 3;
5256 point++;
5258 } while(point <= outline->contours[contour] &&
5259 (outline->tags[point] & FT_Curve_Tag_On) ==
5260 (outline->tags[point-1] & FT_Curve_Tag_On));
5261 /* At the end of a contour Windows adds the start point,
5262 but only for Beziers and we've already done that.
5264 if(point <= outline->contours[contour] &&
5265 outline->tags[point] & FT_Curve_Tag_On) {
5266 /* This is the closing pt of a bezier, but we've already
5267 added it, so just inc point and carry on */
5268 point++;
5270 if(buf) {
5271 ppc->wType = type;
5272 ppc->cpfx = cpfx;
5274 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5276 if(buf)
5277 pph->cb = needed - pph_start;
5279 break;
5282 default:
5283 FIXME("Unsupported format %d\n", format);
5284 LeaveCriticalSection( &freetype_cs );
5285 return GDI_ERROR;
5287 LeaveCriticalSection( &freetype_cs );
5288 return needed;
5291 static BOOL get_bitmap_text_metrics(GdiFont *font)
5293 FT_Face ft_face = font->ft_face;
5294 #ifdef HAVE_FREETYPE_FTWINFNT_H
5295 FT_WinFNT_HeaderRec winfnt_header;
5296 #endif
5297 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5298 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5299 font->potm->otmSize = size;
5301 #define TM font->potm->otmTextMetrics
5302 #ifdef HAVE_FREETYPE_FTWINFNT_H
5303 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5305 TM.tmHeight = winfnt_header.pixel_height;
5306 TM.tmAscent = winfnt_header.ascent;
5307 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5308 TM.tmInternalLeading = winfnt_header.internal_leading;
5309 TM.tmExternalLeading = winfnt_header.external_leading;
5310 TM.tmAveCharWidth = winfnt_header.avg_width;
5311 TM.tmMaxCharWidth = winfnt_header.max_width;
5312 TM.tmWeight = winfnt_header.weight;
5313 TM.tmOverhang = 0;
5314 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5315 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5316 TM.tmFirstChar = winfnt_header.first_char;
5317 TM.tmLastChar = winfnt_header.last_char;
5318 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5319 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5320 TM.tmItalic = winfnt_header.italic;
5321 TM.tmUnderlined = font->underline;
5322 TM.tmStruckOut = font->strikeout;
5323 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5324 TM.tmCharSet = winfnt_header.charset;
5326 else
5327 #endif
5329 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5330 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5331 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5332 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5333 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5334 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5335 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5336 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5337 TM.tmOverhang = 0;
5338 TM.tmDigitizedAspectX = 96; /* FIXME */
5339 TM.tmDigitizedAspectY = 96; /* FIXME */
5340 TM.tmFirstChar = 1;
5341 TM.tmLastChar = 255;
5342 TM.tmDefaultChar = 32;
5343 TM.tmBreakChar = 32;
5344 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5345 TM.tmUnderlined = font->underline;
5346 TM.tmStruckOut = font->strikeout;
5347 /* NB inverted meaning of TMPF_FIXED_PITCH */
5348 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5349 TM.tmCharSet = font->charset;
5351 #undef TM
5353 return TRUE;
5357 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5359 double scale_x, scale_y;
5361 if (font->aveWidth)
5363 scale_x = (double)font->aveWidth;
5364 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5366 else
5367 scale_x = font->scale_y;
5369 scale_x *= fabs(font->font_desc.matrix.eM11);
5370 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5372 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5373 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5375 SCALE_Y(ptm->tmHeight);
5376 SCALE_Y(ptm->tmAscent);
5377 SCALE_Y(ptm->tmDescent);
5378 SCALE_Y(ptm->tmInternalLeading);
5379 SCALE_Y(ptm->tmExternalLeading);
5380 SCALE_Y(ptm->tmOverhang);
5382 SCALE_X(ptm->tmAveCharWidth);
5383 SCALE_X(ptm->tmMaxCharWidth);
5385 #undef SCALE_X
5386 #undef SCALE_Y
5389 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5391 double scale_x, scale_y;
5393 if (font->aveWidth)
5395 scale_x = (double)font->aveWidth;
5396 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5398 else
5399 scale_x = font->scale_y;
5401 scale_x *= fabs(font->font_desc.matrix.eM11);
5402 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5404 scale_font_metrics(font, &potm->otmTextMetrics);
5406 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5407 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5409 SCALE_Y(potm->otmAscent);
5410 SCALE_Y(potm->otmDescent);
5411 SCALE_Y(potm->otmLineGap);
5412 SCALE_Y(potm->otmsCapEmHeight);
5413 SCALE_Y(potm->otmsXHeight);
5414 SCALE_Y(potm->otmrcFontBox.top);
5415 SCALE_Y(potm->otmrcFontBox.bottom);
5416 SCALE_X(potm->otmrcFontBox.left);
5417 SCALE_X(potm->otmrcFontBox.right);
5418 SCALE_Y(potm->otmMacAscent);
5419 SCALE_Y(potm->otmMacDescent);
5420 SCALE_Y(potm->otmMacLineGap);
5421 SCALE_X(potm->otmptSubscriptSize.x);
5422 SCALE_Y(potm->otmptSubscriptSize.y);
5423 SCALE_X(potm->otmptSubscriptOffset.x);
5424 SCALE_Y(potm->otmptSubscriptOffset.y);
5425 SCALE_X(potm->otmptSuperscriptSize.x);
5426 SCALE_Y(potm->otmptSuperscriptSize.y);
5427 SCALE_X(potm->otmptSuperscriptOffset.x);
5428 SCALE_Y(potm->otmptSuperscriptOffset.y);
5429 SCALE_Y(potm->otmsStrikeoutSize);
5430 SCALE_Y(potm->otmsStrikeoutPosition);
5431 SCALE_Y(potm->otmsUnderscoreSize);
5432 SCALE_Y(potm->otmsUnderscorePosition);
5434 #undef SCALE_X
5435 #undef SCALE_Y
5438 /*************************************************************
5439 * WineEngGetTextMetrics
5442 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5444 GDI_CheckNotLock();
5445 EnterCriticalSection( &freetype_cs );
5446 if(!font->potm) {
5447 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5448 if(!get_bitmap_text_metrics(font))
5450 LeaveCriticalSection( &freetype_cs );
5451 return FALSE;
5454 /* Make sure that the font has sane width/height ratio */
5455 if (font->aveWidth)
5457 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5459 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5460 font->aveWidth = 0;
5465 *ptm = font->potm->otmTextMetrics;
5466 scale_font_metrics(font, ptm);
5467 LeaveCriticalSection( &freetype_cs );
5468 return TRUE;
5471 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5473 int i;
5475 for(i = 0; i < ft_face->num_charmaps; i++)
5477 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5478 return TRUE;
5480 return FALSE;
5483 /*************************************************************
5484 * WineEngGetOutlineTextMetrics
5487 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5488 OUTLINETEXTMETRICW *potm)
5490 FT_Face ft_face = font->ft_face;
5491 UINT needed, lenfam, lensty, ret;
5492 TT_OS2 *pOS2;
5493 TT_HoriHeader *pHori;
5494 TT_Postscript *pPost;
5495 FT_Fixed x_scale, y_scale;
5496 WCHAR *family_nameW, *style_nameW;
5497 static const WCHAR spaceW[] = {' ', '\0'};
5498 char *cp;
5499 INT ascent, descent;
5501 TRACE("font=%p\n", font);
5503 if(!FT_IS_SCALABLE(ft_face))
5504 return 0;
5506 GDI_CheckNotLock();
5507 EnterCriticalSection( &freetype_cs );
5509 if(font->potm) {
5510 if(cbSize >= font->potm->otmSize)
5512 memcpy(potm, font->potm, font->potm->otmSize);
5513 scale_outline_font_metrics(font, potm);
5515 LeaveCriticalSection( &freetype_cs );
5516 return font->potm->otmSize;
5520 needed = sizeof(*potm);
5522 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5523 family_nameW = strdupW(font->name);
5525 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5526 * sizeof(WCHAR);
5527 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5528 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5529 style_nameW, lensty/sizeof(WCHAR));
5531 /* These names should be read from the TT name table */
5533 /* length of otmpFamilyName */
5534 needed += lenfam;
5536 /* length of otmpFaceName */
5537 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5538 needed += lenfam; /* just the family name */
5539 } else {
5540 needed += lenfam + lensty; /* family + " " + style */
5543 /* length of otmpStyleName */
5544 needed += lensty;
5546 /* length of otmpFullName */
5547 needed += lenfam + lensty;
5550 x_scale = ft_face->size->metrics.x_scale;
5551 y_scale = ft_face->size->metrics.y_scale;
5553 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5554 if(!pOS2) {
5555 FIXME("Can't find OS/2 table - not TT font?\n");
5556 ret = 0;
5557 goto end;
5560 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5561 if(!pHori) {
5562 FIXME("Can't find HHEA table - not TT font?\n");
5563 ret = 0;
5564 goto end;
5567 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5569 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",
5570 pOS2->usWinAscent, pOS2->usWinDescent,
5571 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5572 ft_face->ascender, ft_face->descender, ft_face->height,
5573 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5574 ft_face->bbox.yMax, ft_face->bbox.yMin);
5576 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5577 font->potm->otmSize = needed;
5579 #define TM font->potm->otmTextMetrics
5581 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5582 ascent = pHori->Ascender;
5583 descent = -pHori->Descender;
5584 } else {
5585 ascent = pOS2->usWinAscent;
5586 descent = pOS2->usWinDescent;
5589 if(font->yMax) {
5590 TM.tmAscent = font->yMax;
5591 TM.tmDescent = -font->yMin;
5592 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5593 } else {
5594 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5595 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5596 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5597 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5600 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5602 /* MSDN says:
5603 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5605 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5606 ((ascent + descent) -
5607 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5609 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5610 if (TM.tmAveCharWidth == 0) {
5611 TM.tmAveCharWidth = 1;
5613 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5614 TM.tmWeight = FW_REGULAR;
5615 if (font->fake_bold)
5616 TM.tmWeight = FW_BOLD;
5617 else
5619 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5621 if (pOS2->usWeightClass > FW_MEDIUM)
5622 TM.tmWeight = pOS2->usWeightClass;
5624 else if (pOS2->usWeightClass <= FW_MEDIUM)
5625 TM.tmWeight = pOS2->usWeightClass;
5627 TM.tmOverhang = 0;
5628 TM.tmDigitizedAspectX = 300;
5629 TM.tmDigitizedAspectY = 300;
5630 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5631 * symbol range to 0 - f0ff
5634 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5636 TM.tmFirstChar = 0;
5637 switch(GetACP())
5639 case 1257: /* Baltic */
5640 TM.tmLastChar = 0xf8fd;
5641 break;
5642 default:
5643 TM.tmLastChar = 0xf0ff;
5645 TM.tmBreakChar = 0x20;
5646 TM.tmDefaultChar = 0x1f;
5648 else
5650 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5651 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5653 if(pOS2->usFirstCharIndex <= 1)
5654 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5655 else if (pOS2->usFirstCharIndex > 0xff)
5656 TM.tmBreakChar = 0x20;
5657 else
5658 TM.tmBreakChar = pOS2->usFirstCharIndex;
5659 TM.tmDefaultChar = TM.tmBreakChar - 1;
5661 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5662 TM.tmUnderlined = font->underline;
5663 TM.tmStruckOut = font->strikeout;
5665 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5666 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5667 (pOS2->version == 0xFFFFU ||
5668 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5669 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5670 else
5671 TM.tmPitchAndFamily = 0;
5673 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5675 case PAN_FAMILY_SCRIPT:
5676 TM.tmPitchAndFamily |= FF_SCRIPT;
5677 break;
5679 case PAN_FAMILY_DECORATIVE:
5680 TM.tmPitchAndFamily |= FF_DECORATIVE;
5681 break;
5683 case PAN_ANY:
5684 case PAN_NO_FIT:
5685 case PAN_FAMILY_TEXT_DISPLAY:
5686 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5687 /* which is clearly not what the panose spec says. */
5688 default:
5689 if(TM.tmPitchAndFamily == 0 || /* fixed */
5690 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5691 TM.tmPitchAndFamily = FF_MODERN;
5692 else
5694 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5696 case PAN_ANY:
5697 case PAN_NO_FIT:
5698 default:
5699 TM.tmPitchAndFamily |= FF_DONTCARE;
5700 break;
5702 case PAN_SERIF_COVE:
5703 case PAN_SERIF_OBTUSE_COVE:
5704 case PAN_SERIF_SQUARE_COVE:
5705 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5706 case PAN_SERIF_SQUARE:
5707 case PAN_SERIF_THIN:
5708 case PAN_SERIF_BONE:
5709 case PAN_SERIF_EXAGGERATED:
5710 case PAN_SERIF_TRIANGLE:
5711 TM.tmPitchAndFamily |= FF_ROMAN;
5712 break;
5714 case PAN_SERIF_NORMAL_SANS:
5715 case PAN_SERIF_OBTUSE_SANS:
5716 case PAN_SERIF_PERP_SANS:
5717 case PAN_SERIF_FLARED:
5718 case PAN_SERIF_ROUNDED:
5719 TM.tmPitchAndFamily |= FF_SWISS;
5720 break;
5723 break;
5726 if(FT_IS_SCALABLE(ft_face))
5727 TM.tmPitchAndFamily |= TMPF_VECTOR;
5729 if(FT_IS_SFNT(ft_face))
5731 if (font->ntmFlags & NTM_PS_OPENTYPE)
5732 TM.tmPitchAndFamily |= TMPF_DEVICE;
5733 else
5734 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5737 TM.tmCharSet = font->charset;
5739 font->potm->otmFiller = 0;
5740 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5741 font->potm->otmfsSelection = pOS2->fsSelection;
5742 font->potm->otmfsType = pOS2->fsType;
5743 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5744 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5745 font->potm->otmItalicAngle = 0; /* POST table */
5746 font->potm->otmEMSquare = ft_face->units_per_EM;
5747 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5748 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5749 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5750 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5751 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5752 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5753 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5754 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5755 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5756 font->potm->otmMacAscent = TM.tmAscent;
5757 font->potm->otmMacDescent = -TM.tmDescent;
5758 font->potm->otmMacLineGap = font->potm->otmLineGap;
5759 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5760 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5761 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5762 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5763 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5764 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5765 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5766 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5767 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5768 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5769 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5770 if(!pPost) {
5771 font->potm->otmsUnderscoreSize = 0;
5772 font->potm->otmsUnderscorePosition = 0;
5773 } else {
5774 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5775 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5777 #undef TM
5779 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5780 cp = (char*)font->potm + sizeof(*font->potm);
5781 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5782 strcpyW((WCHAR*)cp, family_nameW);
5783 cp += lenfam;
5784 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5785 strcpyW((WCHAR*)cp, style_nameW);
5786 cp += lensty;
5787 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5788 strcpyW((WCHAR*)cp, family_nameW);
5789 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5790 strcatW((WCHAR*)cp, spaceW);
5791 strcatW((WCHAR*)cp, style_nameW);
5792 cp += lenfam + lensty;
5793 } else
5794 cp += lenfam;
5795 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5796 strcpyW((WCHAR*)cp, family_nameW);
5797 strcatW((WCHAR*)cp, spaceW);
5798 strcatW((WCHAR*)cp, style_nameW);
5799 ret = needed;
5801 if(potm && needed <= cbSize)
5803 memcpy(potm, font->potm, font->potm->otmSize);
5804 scale_outline_font_metrics(font, potm);
5807 end:
5808 HeapFree(GetProcessHeap(), 0, style_nameW);
5809 HeapFree(GetProcessHeap(), 0, family_nameW);
5811 LeaveCriticalSection( &freetype_cs );
5812 return ret;
5815 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5817 HFONTLIST *hfontlist;
5818 child->font = alloc_font();
5819 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5820 if(!child->font->ft_face)
5822 free_font(child->font);
5823 child->font = NULL;
5824 return FALSE;
5827 child->font->font_desc = font->font_desc;
5828 child->font->ntmFlags = child->face->ntmFlags;
5829 child->font->orientation = font->orientation;
5830 child->font->scale_y = font->scale_y;
5831 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5832 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5833 child->font->name = strdupW(child->face->family->FamilyName);
5834 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5835 child->font->base_font = font;
5836 list_add_head(&child_font_list, &child->font->entry);
5837 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5838 return TRUE;
5841 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5843 FT_UInt g;
5844 CHILD_FONT *child_font;
5846 if(font->base_font)
5847 font = font->base_font;
5849 *linked_font = font;
5851 if((*glyph = get_glyph_index(font, c)))
5852 return TRUE;
5854 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5856 if(!child_font->font)
5857 if(!load_child_font(font, child_font))
5858 continue;
5860 if(!child_font->font->ft_face)
5861 continue;
5862 g = get_glyph_index(child_font->font, c);
5863 if(g)
5865 *glyph = g;
5866 *linked_font = child_font->font;
5867 return TRUE;
5870 return FALSE;
5873 /*************************************************************
5874 * WineEngGetCharWidth
5877 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5878 LPINT buffer)
5880 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5881 UINT c;
5882 GLYPHMETRICS gm;
5883 FT_UInt glyph_index;
5884 GdiFont *linked_font;
5886 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5888 GDI_CheckNotLock();
5889 EnterCriticalSection( &freetype_cs );
5890 for(c = firstChar; c <= lastChar; c++) {
5891 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5892 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5893 &gm, 0, NULL, &identity);
5894 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5896 LeaveCriticalSection( &freetype_cs );
5897 return TRUE;
5900 /*************************************************************
5901 * WineEngGetCharABCWidths
5904 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5905 LPABC buffer)
5907 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5908 UINT c;
5909 GLYPHMETRICS gm;
5910 FT_UInt glyph_index;
5911 GdiFont *linked_font;
5913 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5915 if(!FT_IS_SCALABLE(font->ft_face))
5916 return FALSE;
5918 GDI_CheckNotLock();
5919 EnterCriticalSection( &freetype_cs );
5921 for(c = firstChar; c <= lastChar; c++) {
5922 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5923 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5924 &gm, 0, NULL, &identity);
5925 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5926 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5927 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5928 FONT_GM(linked_font,glyph_index)->bbx;
5930 LeaveCriticalSection( &freetype_cs );
5931 return TRUE;
5934 /*************************************************************
5935 * WineEngGetCharABCWidthsFloat
5938 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
5940 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
5941 UINT c;
5942 GLYPHMETRICS gm;
5943 FT_UInt glyph_index;
5944 GdiFont *linked_font;
5946 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
5948 GDI_CheckNotLock();
5949 EnterCriticalSection( &freetype_cs );
5951 for (c = first; c <= last; c++)
5953 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5954 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5955 &gm, 0, NULL, &identity);
5956 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
5957 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
5958 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
5959 FONT_GM(linked_font, glyph_index)->lsb -
5960 FONT_GM(linked_font, glyph_index)->bbx;
5962 LeaveCriticalSection( &freetype_cs );
5963 return TRUE;
5966 /*************************************************************
5967 * WineEngGetCharABCWidthsI
5970 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5971 LPABC buffer)
5973 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5974 UINT c;
5975 GLYPHMETRICS gm;
5976 FT_UInt glyph_index;
5977 GdiFont *linked_font;
5979 if(!FT_HAS_HORIZONTAL(font->ft_face))
5980 return FALSE;
5982 GDI_CheckNotLock();
5983 EnterCriticalSection( &freetype_cs );
5985 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5986 if (!pgi)
5987 for(c = firstChar; c < firstChar+count; c++) {
5988 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5989 &gm, 0, NULL, &identity);
5990 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5991 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5992 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5993 - FONT_GM(linked_font,c)->bbx;
5995 else
5996 for(c = 0; c < count; c++) {
5997 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5998 &gm, 0, NULL, &identity);
5999 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6000 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6001 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6002 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6005 LeaveCriticalSection( &freetype_cs );
6006 return TRUE;
6009 /*************************************************************
6010 * WineEngGetTextExtentExPoint
6013 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6014 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6016 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6017 INT idx;
6018 INT nfit = 0, ext;
6019 GLYPHMETRICS gm;
6020 TEXTMETRICW tm;
6021 FT_UInt glyph_index;
6022 GdiFont *linked_font;
6024 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6025 max_ext, size);
6027 GDI_CheckNotLock();
6028 EnterCriticalSection( &freetype_cs );
6030 size->cx = 0;
6031 WineEngGetTextMetrics(font, &tm);
6032 size->cy = tm.tmHeight;
6034 for(idx = 0; idx < count; idx++) {
6035 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6036 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6037 &gm, 0, NULL, &identity);
6038 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6039 ext = size->cx;
6040 if (! pnfit || ext <= max_ext) {
6041 ++nfit;
6042 if (dxs)
6043 dxs[idx] = ext;
6047 if (pnfit)
6048 *pnfit = nfit;
6050 LeaveCriticalSection( &freetype_cs );
6051 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6052 return TRUE;
6055 /*************************************************************
6056 * WineEngGetTextExtentExPointI
6059 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6060 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6062 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6063 INT idx;
6064 INT nfit = 0, ext;
6065 GLYPHMETRICS gm;
6066 TEXTMETRICW tm;
6068 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6070 GDI_CheckNotLock();
6071 EnterCriticalSection( &freetype_cs );
6073 size->cx = 0;
6074 WineEngGetTextMetrics(font, &tm);
6075 size->cy = tm.tmHeight;
6077 for(idx = 0; idx < count; idx++) {
6078 WineEngGetGlyphOutline(font, indices[idx],
6079 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6080 &identity);
6081 size->cx += FONT_GM(font,indices[idx])->adv;
6082 ext = size->cx;
6083 if (! pnfit || ext <= max_ext) {
6084 ++nfit;
6085 if (dxs)
6086 dxs[idx] = ext;
6090 if (pnfit)
6091 *pnfit = nfit;
6093 LeaveCriticalSection( &freetype_cs );
6094 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6095 return TRUE;
6098 /*************************************************************
6099 * WineEngGetFontData
6102 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6103 DWORD cbData)
6105 FT_Face ft_face = font->ft_face;
6106 FT_ULong len;
6107 FT_Error err;
6109 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6110 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6111 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6113 if(!FT_IS_SFNT(ft_face))
6114 return GDI_ERROR;
6116 if(!buf || !cbData)
6117 len = 0;
6118 else
6119 len = cbData;
6121 if(table) { /* MS tags differ in endianness from FT ones */
6122 table = table >> 24 | table << 24 |
6123 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6126 /* make sure value of len is the value freetype says it needs */
6127 if(buf && len)
6129 FT_ULong needed = 0;
6130 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6131 if( !err && needed < len) len = needed;
6133 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6135 if(err) {
6136 TRACE("Can't find table %c%c%c%c\n",
6137 /* bytes were reversed */
6138 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6139 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6140 return GDI_ERROR;
6142 return len;
6145 /*************************************************************
6146 * WineEngGetTextFace
6149 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6151 INT n = strlenW(font->name) + 1;
6152 if(str) {
6153 lstrcpynW(str, font->name, count);
6154 return min(count, n);
6155 } else
6156 return n;
6159 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6161 if (fs) *fs = font->fs;
6162 return font->charset;
6165 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6167 GdiFont *font = dc->gdiFont, *linked_font;
6168 struct list *first_hfont;
6169 BOOL ret;
6171 GDI_CheckNotLock();
6172 EnterCriticalSection( &freetype_cs );
6173 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6174 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6175 if(font == linked_font)
6176 *new_hfont = dc->hFont;
6177 else
6179 first_hfont = list_head(&linked_font->hfontlist);
6180 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6182 LeaveCriticalSection( &freetype_cs );
6183 return ret;
6186 /* Retrieve a list of supported Unicode ranges for a given font.
6187 * Can be called with NULL gs to calculate the buffer size. Returns
6188 * the number of ranges found.
6190 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6192 DWORD num_ranges = 0;
6194 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6196 FT_UInt glyph_code;
6197 FT_ULong char_code, char_code_prev;
6199 glyph_code = 0;
6200 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6202 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6203 face->num_glyphs, glyph_code, char_code);
6205 if (!glyph_code) return 0;
6207 if (gs)
6209 gs->ranges[0].wcLow = (USHORT)char_code;
6210 gs->ranges[0].cGlyphs = 0;
6211 gs->cGlyphsSupported = 0;
6214 num_ranges = 1;
6215 while (glyph_code)
6217 if (char_code < char_code_prev)
6219 ERR("expected increasing char code from FT_Get_Next_Char\n");
6220 return 0;
6222 if (char_code - char_code_prev > 1)
6224 num_ranges++;
6225 if (gs)
6227 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6228 gs->ranges[num_ranges - 1].cGlyphs = 1;
6229 gs->cGlyphsSupported++;
6232 else if (gs)
6234 gs->ranges[num_ranges - 1].cGlyphs++;
6235 gs->cGlyphsSupported++;
6237 char_code_prev = char_code;
6238 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6241 else
6242 FIXME("encoding %u not supported\n", face->charmap->encoding);
6244 return num_ranges;
6247 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6249 DWORD size = 0;
6250 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6252 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6253 if (glyphset)
6255 glyphset->cbThis = size;
6256 glyphset->cRanges = num_ranges;
6258 return size;
6261 /*************************************************************
6262 * FontIsLinked
6264 BOOL WineEngFontIsLinked(GdiFont *font)
6266 BOOL ret;
6267 GDI_CheckNotLock();
6268 EnterCriticalSection( &freetype_cs );
6269 ret = !list_empty(&font->child_fonts);
6270 LeaveCriticalSection( &freetype_cs );
6271 return ret;
6274 static BOOL is_hinting_enabled(void)
6276 /* Use the >= 2.2.0 function if available */
6277 if(pFT_Get_TrueType_Engine_Type)
6279 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6280 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6282 #ifdef FT_DRIVER_HAS_HINTER
6283 else
6285 FT_Module mod;
6287 /* otherwise if we've been compiled with < 2.2.0 headers
6288 use the internal macro */
6289 mod = pFT_Get_Module(library, "truetype");
6290 if(mod && FT_DRIVER_HAS_HINTER(mod))
6291 return TRUE;
6293 #endif
6295 return FALSE;
6298 static BOOL is_subpixel_rendering_enabled( void )
6300 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6301 return pFT_Library_SetLcdFilter &&
6302 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6303 #else
6304 return FALSE;
6305 #endif
6308 /*************************************************************************
6309 * GetRasterizerCaps (GDI32.@)
6311 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6313 static int hinting = -1;
6314 static int subpixel = -1;
6316 if(hinting == -1)
6318 hinting = is_hinting_enabled();
6319 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6322 if ( subpixel == -1 )
6324 subpixel = is_subpixel_rendering_enabled();
6325 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6328 lprs->nSize = sizeof(RASTERIZER_STATUS);
6329 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6330 if ( subpixel )
6331 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6332 lprs->nLanguageID = 0;
6333 return TRUE;
6336 /*************************************************************
6337 * WineEngRealizationInfo
6339 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6341 FIXME("(%p, %p): stub!\n", font, info);
6343 info->flags = 1;
6344 if(FT_IS_SCALABLE(font->ft_face))
6345 info->flags |= 2;
6347 info->cache_num = font->cache_num;
6348 info->unknown2 = -1;
6349 return TRUE;
6352 /*************************************************************************
6353 * Kerning support for TrueType fonts
6355 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6357 struct TT_kern_table
6359 USHORT version;
6360 USHORT nTables;
6363 struct TT_kern_subtable
6365 USHORT version;
6366 USHORT length;
6367 union
6369 USHORT word;
6370 struct
6372 USHORT horizontal : 1;
6373 USHORT minimum : 1;
6374 USHORT cross_stream: 1;
6375 USHORT override : 1;
6376 USHORT reserved1 : 4;
6377 USHORT format : 8;
6378 } bits;
6379 } coverage;
6382 struct TT_format0_kern_subtable
6384 USHORT nPairs;
6385 USHORT searchRange;
6386 USHORT entrySelector;
6387 USHORT rangeShift;
6390 struct TT_kern_pair
6392 USHORT left;
6393 USHORT right;
6394 short value;
6397 static DWORD parse_format0_kern_subtable(GdiFont *font,
6398 const struct TT_format0_kern_subtable *tt_f0_ks,
6399 const USHORT *glyph_to_char,
6400 KERNINGPAIR *kern_pair, DWORD cPairs)
6402 USHORT i, nPairs;
6403 const struct TT_kern_pair *tt_kern_pair;
6405 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6407 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6409 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6410 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6411 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6413 if (!kern_pair || !cPairs)
6414 return nPairs;
6416 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6418 nPairs = min(nPairs, cPairs);
6420 for (i = 0; i < nPairs; i++)
6422 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6423 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6424 /* this algorithm appears to better match what Windows does */
6425 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6426 if (kern_pair->iKernAmount < 0)
6428 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6429 kern_pair->iKernAmount -= font->ppem;
6431 else if (kern_pair->iKernAmount > 0)
6433 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6434 kern_pair->iKernAmount += font->ppem;
6436 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6438 TRACE("left %u right %u value %d\n",
6439 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6441 kern_pair++;
6443 TRACE("copied %u entries\n", nPairs);
6444 return nPairs;
6447 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6449 DWORD length;
6450 void *buf;
6451 const struct TT_kern_table *tt_kern_table;
6452 const struct TT_kern_subtable *tt_kern_subtable;
6453 USHORT i, nTables;
6454 USHORT *glyph_to_char;
6456 GDI_CheckNotLock();
6457 EnterCriticalSection( &freetype_cs );
6458 if (font->total_kern_pairs != (DWORD)-1)
6460 if (cPairs && kern_pair)
6462 cPairs = min(cPairs, font->total_kern_pairs);
6463 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6464 LeaveCriticalSection( &freetype_cs );
6465 return cPairs;
6467 LeaveCriticalSection( &freetype_cs );
6468 return font->total_kern_pairs;
6471 font->total_kern_pairs = 0;
6473 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6475 if (length == GDI_ERROR)
6477 TRACE("no kerning data in the font\n");
6478 LeaveCriticalSection( &freetype_cs );
6479 return 0;
6482 buf = HeapAlloc(GetProcessHeap(), 0, length);
6483 if (!buf)
6485 WARN("Out of memory\n");
6486 LeaveCriticalSection( &freetype_cs );
6487 return 0;
6490 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6492 /* build a glyph index to char code map */
6493 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6494 if (!glyph_to_char)
6496 WARN("Out of memory allocating a glyph index to char code map\n");
6497 HeapFree(GetProcessHeap(), 0, buf);
6498 LeaveCriticalSection( &freetype_cs );
6499 return 0;
6502 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6504 FT_UInt glyph_code;
6505 FT_ULong char_code;
6507 glyph_code = 0;
6508 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6510 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6511 font->ft_face->num_glyphs, glyph_code, char_code);
6513 while (glyph_code)
6515 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6517 /* FIXME: This doesn't match what Windows does: it does some fancy
6518 * things with duplicate glyph index to char code mappings, while
6519 * we just avoid overriding existing entries.
6521 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6522 glyph_to_char[glyph_code] = (USHORT)char_code;
6524 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6527 else
6529 ULONG n;
6531 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6532 for (n = 0; n <= 65535; n++)
6533 glyph_to_char[n] = (USHORT)n;
6536 tt_kern_table = buf;
6537 nTables = GET_BE_WORD(tt_kern_table->nTables);
6538 TRACE("version %u, nTables %u\n",
6539 GET_BE_WORD(tt_kern_table->version), nTables);
6541 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6543 for (i = 0; i < nTables; i++)
6545 struct TT_kern_subtable tt_kern_subtable_copy;
6547 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6548 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6549 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6551 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6552 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6553 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6555 /* According to the TrueType specification this is the only format
6556 * that will be properly interpreted by Windows and OS/2
6558 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6560 DWORD new_chunk, old_total = font->total_kern_pairs;
6562 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6563 glyph_to_char, NULL, 0);
6564 font->total_kern_pairs += new_chunk;
6566 if (!font->kern_pairs)
6567 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6568 font->total_kern_pairs * sizeof(*font->kern_pairs));
6569 else
6570 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6571 font->total_kern_pairs * sizeof(*font->kern_pairs));
6573 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6574 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6576 else
6577 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6579 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6582 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6583 HeapFree(GetProcessHeap(), 0, buf);
6585 if (cPairs && kern_pair)
6587 cPairs = min(cPairs, font->total_kern_pairs);
6588 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6589 LeaveCriticalSection( &freetype_cs );
6590 return cPairs;
6592 LeaveCriticalSection( &freetype_cs );
6593 return font->total_kern_pairs;
6596 #else /* HAVE_FREETYPE */
6598 /*************************************************************************/
6600 BOOL WineEngInit(void)
6602 return FALSE;
6604 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6606 return NULL;
6608 BOOL WineEngDestroyFontInstance(HFONT hfont)
6610 return FALSE;
6613 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6615 return 1;
6618 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6619 LPWORD pgi, DWORD flags)
6621 return GDI_ERROR;
6624 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6625 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6626 const MAT2* lpmat)
6628 ERR("called but we don't have FreeType\n");
6629 return GDI_ERROR;
6632 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6634 ERR("called but we don't have FreeType\n");
6635 return FALSE;
6638 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6639 OUTLINETEXTMETRICW *potm)
6641 ERR("called but we don't have FreeType\n");
6642 return 0;
6645 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6646 LPINT buffer)
6648 ERR("called but we don't have FreeType\n");
6649 return FALSE;
6652 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6653 LPABC buffer)
6655 ERR("called but we don't have FreeType\n");
6656 return FALSE;
6659 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6661 ERR("called but we don't have FreeType\n");
6662 return FALSE;
6665 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6666 LPABC buffer)
6668 ERR("called but we don't have FreeType\n");
6669 return FALSE;
6672 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6673 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6675 ERR("called but we don't have FreeType\n");
6676 return FALSE;
6679 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6680 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6682 ERR("called but we don't have FreeType\n");
6683 return FALSE;
6686 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6687 DWORD cbData)
6689 ERR("called but we don't have FreeType\n");
6690 return GDI_ERROR;
6693 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6695 ERR("called but we don't have FreeType\n");
6696 return 0;
6699 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6701 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6702 return 1;
6705 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6707 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6708 return TRUE;
6711 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6713 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6714 return NULL;
6717 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6719 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6720 return DEFAULT_CHARSET;
6723 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6725 return FALSE;
6728 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6730 FIXME("(%p, %p): stub\n", font, glyphset);
6731 return 0;
6734 BOOL WineEngFontIsLinked(GdiFont *font)
6736 return FALSE;
6739 /*************************************************************************
6740 * GetRasterizerCaps (GDI32.@)
6742 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6744 lprs->nSize = sizeof(RASTERIZER_STATUS);
6745 lprs->wFlags = 0;
6746 lprs->nLanguageID = 0;
6747 return TRUE;
6750 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6752 ERR("called but we don't have FreeType\n");
6753 return 0;
6756 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6758 ERR("called but we don't have FreeType\n");
6759 return FALSE;
6762 #endif /* HAVE_FREETYPE */