gdi32: Rework the test for too large width/height font ratio to pass with different...
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob9b5f44fd7d206594787b80d3b737d96feb9e5f51
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/unicode.h"
88 #include "wine/debug.h"
89 #include "wine/list.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FREETYPE
95 #ifdef HAVE_FT2BUILD_H
96 #include <ft2build.h>
97 #endif
98 #ifdef HAVE_FREETYPE_FREETYPE_H
99 #include <freetype/freetype.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FTGLYPH_H
102 #include <freetype/ftglyph.h>
103 #endif
104 #ifdef HAVE_FREETYPE_TTTABLES_H
105 #include <freetype/tttables.h>
106 #endif
107 #ifdef HAVE_FREETYPE_FTTYPES_H
108 #include <freetype/fttypes.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTSNAMES_H
111 #include <freetype/ftsnames.h>
112 #endif
113 #ifdef HAVE_FREETYPE_TTNAMEID_H
114 #include <freetype/ttnameid.h>
115 #endif
116 #ifdef HAVE_FREETYPE_FTOUTLN_H
117 #include <freetype/ftoutln.h>
118 #endif
119 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
120 #include <freetype/internal/sfnt.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 #ifdef FT_MULFIX_INLINED
168 #define pFT_MulFix FT_MULFIX_INLINED
169 #else
170 MAKE_FUNCPTR(FT_MulFix);
171 #endif
172 MAKE_FUNCPTR(FT_New_Face);
173 MAKE_FUNCPTR(FT_New_Memory_Face);
174 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
175 MAKE_FUNCPTR(FT_Outline_Transform);
176 MAKE_FUNCPTR(FT_Outline_Translate);
177 MAKE_FUNCPTR(FT_Select_Charmap);
178 MAKE_FUNCPTR(FT_Set_Charmap);
179 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
180 MAKE_FUNCPTR(FT_Vector_Transform);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
183 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
184 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
185 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
186 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
187 #ifdef HAVE_FREETYPE_FTLCDFIL_H
188 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
189 #endif
190 #ifdef HAVE_FREETYPE_FTWINFNT_H
191 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
192 #endif
194 #ifdef SONAME_LIBFONTCONFIG
195 #include <fontconfig/fontconfig.h>
196 MAKE_FUNCPTR(FcConfigGetCurrent);
197 MAKE_FUNCPTR(FcFontList);
198 MAKE_FUNCPTR(FcFontSetDestroy);
199 MAKE_FUNCPTR(FcInit);
200 MAKE_FUNCPTR(FcObjectSetAdd);
201 MAKE_FUNCPTR(FcObjectSetCreate);
202 MAKE_FUNCPTR(FcObjectSetDestroy);
203 MAKE_FUNCPTR(FcPatternCreate);
204 MAKE_FUNCPTR(FcPatternDestroy);
205 MAKE_FUNCPTR(FcPatternGetBool);
206 MAKE_FUNCPTR(FcPatternGetString);
207 #endif
209 #undef MAKE_FUNCPTR
211 #ifndef FT_MAKE_TAG
212 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
213 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
214 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #endif
217 #ifndef ft_encoding_none
218 #define FT_ENCODING_NONE ft_encoding_none
219 #endif
220 #ifndef ft_encoding_ms_symbol
221 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #endif
223 #ifndef ft_encoding_unicode
224 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #endif
226 #ifndef ft_encoding_apple_roman
227 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #endif
230 #ifdef WORDS_BIGENDIAN
231 #define GET_BE_WORD(x) (x)
232 #else
233 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 #endif
236 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
237 typedef struct {
238 FT_Short height;
239 FT_Short width;
240 FT_Pos size;
241 FT_Pos x_ppem;
242 FT_Pos y_ppem;
243 FT_Short internal_leading;
244 } Bitmap_Size;
246 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
247 So to let this compile on older versions of FreeType we'll define the
248 new structure here. */
249 typedef struct {
250 FT_Short height, width;
251 FT_Pos size, x_ppem, y_ppem;
252 } My_FT_Bitmap_Size;
254 struct enum_data
256 ENUMLOGFONTEXW elf;
257 NEWTEXTMETRICEXW ntm;
258 DWORD type;
261 typedef struct tagFace {
262 struct list entry;
263 WCHAR *StyleName;
264 char *file;
265 void *font_data_ptr;
266 DWORD font_data_size;
267 FT_Long face_index;
268 FONTSIGNATURE fs;
269 FONTSIGNATURE fs_links;
270 DWORD ntmFlags;
271 FT_Fixed font_version;
272 BOOL scalable;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
278 } Face;
280 typedef struct tagFamily {
281 struct list entry;
282 const WCHAR *FamilyName;
283 struct list faces;
284 } Family;
286 typedef struct {
287 GLYPHMETRICS gm;
288 INT adv; /* These three hold to widths of the unrotated chars */
289 INT lsb;
290 INT bbx;
291 BOOL init;
292 } GM;
294 typedef struct {
295 FLOAT eM11, eM12;
296 FLOAT eM21, eM22;
297 } FMAT2;
299 typedef struct {
300 DWORD hash;
301 LOGFONTW lf;
302 FMAT2 matrix;
303 BOOL can_use_bitmap;
304 } FONT_DESC;
306 typedef struct tagHFONTLIST {
307 struct list entry;
308 HFONT hfont;
309 } HFONTLIST;
311 typedef struct {
312 struct list entry;
313 Face *face;
314 GdiFont *font;
315 } CHILD_FONT;
317 struct tagGdiFont {
318 struct list entry;
319 GM **gm;
320 DWORD gmsize;
321 struct list hfontlist;
322 OUTLINETEXTMETRICW *potm;
323 DWORD total_kern_pairs;
324 KERNINGPAIR *kern_pairs;
325 struct list child_fonts;
327 /* the following members can be accessed without locking, they are never modified after creation */
328 FT_Face ft_face;
329 struct font_mapping *mapping;
330 LPWSTR name;
331 int charset;
332 int codepage;
333 BOOL fake_italic;
334 BOOL fake_bold;
335 BYTE underline;
336 BYTE strikeout;
337 INT orientation;
338 FONT_DESC font_desc;
339 LONG aveWidth, ppem;
340 double scale_y;
341 SHORT yMax;
342 SHORT yMin;
343 DWORD ntmFlags;
344 FONTSIGNATURE fs;
345 GdiFont *base_font;
346 VOID *GSUB_Table;
347 DWORD cache_num;
350 typedef struct {
351 struct list entry;
352 const WCHAR *font_name;
353 struct list links;
354 } SYSTEM_LINKS;
356 #define GM_BLOCK_SIZE 128
357 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
359 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
360 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
361 #define UNUSED_CACHE_SIZE 10
362 static struct list child_font_list = LIST_INIT(child_font_list);
363 static struct list system_links = LIST_INIT(system_links);
365 static struct list font_subst_list = LIST_INIT(font_subst_list);
367 static struct list font_list = LIST_INIT(font_list);
369 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
370 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
371 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
373 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
374 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
380 'W','i','n','d','o','w','s',' ','N','T','\\',
381 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
382 'F','o','n','t','s','\0'};
384 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
385 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
386 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
387 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
389 static const WCHAR * const SystemFontValues[4] = {
390 System_Value,
391 OEMFont_Value,
392 FixedSys_Value,
393 NULL
396 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
397 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
399 /* Interesting and well-known (frequently-assumed!) font names */
400 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
401 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 };
402 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
403 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
404 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
405 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
406 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
407 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
409 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
410 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
411 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
412 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
413 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
414 'E','u','r','o','p','e','a','n','\0'};
415 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
416 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
417 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
418 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
419 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
420 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
421 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
422 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
423 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
424 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
425 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
426 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
428 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
429 WesternW, /*00*/
430 Central_EuropeanW,
431 CyrillicW,
432 GreekW,
433 TurkishW,
434 HebrewW,
435 ArabicW,
436 BalticW,
437 VietnameseW, /*08*/
438 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
439 ThaiW,
440 JapaneseW,
441 CHINESE_GB2312W,
442 HangulW,
443 CHINESE_BIG5W,
444 Hangul_Johab_W,
445 NULL, NULL, /*23*/
446 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
447 SymbolW /*31*/
450 typedef struct {
451 WCHAR *name;
452 INT charset;
453 } NameCs;
455 typedef struct tagFontSubst {
456 struct list entry;
457 NameCs from;
458 NameCs to;
459 } FontSubst;
461 struct font_mapping
463 struct list entry;
464 int refcount;
465 dev_t dev;
466 ino_t ino;
467 void *data;
468 size_t size;
471 static struct list mappings_list = LIST_INIT( mappings_list );
473 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
475 static CRITICAL_SECTION freetype_cs;
476 static CRITICAL_SECTION_DEBUG critsect_debug =
478 0, 0, &freetype_cs,
479 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
480 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
482 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
484 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
486 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
487 static BOOL use_default_fallback = FALSE;
489 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
491 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
492 'W','i','n','d','o','w','s',' ','N','T','\\',
493 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
494 'S','y','s','t','e','m','L','i','n','k',0};
496 /****************************************
497 * Notes on .fon files
499 * The fonts System, FixedSys and Terminal are special. There are typically multiple
500 * versions installed for different resolutions and codepages. Windows stores which one to use
501 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
502 * Key Meaning
503 * FIXEDFON.FON FixedSys
504 * FONTS.FON System
505 * OEMFONT.FON Terminal
506 * LogPixels Current dpi set by the display control panel applet
507 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
508 * also has a LogPixels value that appears to mirror this)
510 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
511 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
512 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
513 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
514 * so that makes sense.
516 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
517 * to be mapped into the registry on Windows 2000 at least).
518 * I have
519 * woafont=app850.fon
520 * ega80woa.fon=ega80850.fon
521 * ega40woa.fon=ega40850.fon
522 * cga80woa.fon=cga80850.fon
523 * cga40woa.fon=cga40850.fon
526 /* These are all structures needed for the GSUB table */
528 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
529 #define TATEGAKI_LOWER_BOUND 0x02F1
531 typedef struct {
532 DWORD version;
533 WORD ScriptList;
534 WORD FeatureList;
535 WORD LookupList;
536 } GSUB_Header;
538 typedef struct {
539 CHAR ScriptTag[4];
540 WORD Script;
541 } GSUB_ScriptRecord;
543 typedef struct {
544 WORD ScriptCount;
545 GSUB_ScriptRecord ScriptRecord[1];
546 } GSUB_ScriptList;
548 typedef struct {
549 CHAR LangSysTag[4];
550 WORD LangSys;
551 } GSUB_LangSysRecord;
553 typedef struct {
554 WORD DefaultLangSys;
555 WORD LangSysCount;
556 GSUB_LangSysRecord LangSysRecord[1];
557 } GSUB_Script;
559 typedef struct {
560 WORD LookupOrder; /* Reserved */
561 WORD ReqFeatureIndex;
562 WORD FeatureCount;
563 WORD FeatureIndex[1];
564 } GSUB_LangSys;
566 typedef struct {
567 CHAR FeatureTag[4];
568 WORD Feature;
569 } GSUB_FeatureRecord;
571 typedef struct {
572 WORD FeatureCount;
573 GSUB_FeatureRecord FeatureRecord[1];
574 } GSUB_FeatureList;
576 typedef struct {
577 WORD FeatureParams; /* Reserved */
578 WORD LookupCount;
579 WORD LookupListIndex[1];
580 } GSUB_Feature;
582 typedef struct {
583 WORD LookupCount;
584 WORD Lookup[1];
585 } GSUB_LookupList;
587 typedef struct {
588 WORD LookupType;
589 WORD LookupFlag;
590 WORD SubTableCount;
591 WORD SubTable[1];
592 } GSUB_LookupTable;
594 typedef struct {
595 WORD CoverageFormat;
596 WORD GlyphCount;
597 WORD GlyphArray[1];
598 } GSUB_CoverageFormat1;
600 typedef struct {
601 WORD Start;
602 WORD End;
603 WORD StartCoverageIndex;
604 } GSUB_RangeRecord;
606 typedef struct {
607 WORD CoverageFormat;
608 WORD RangeCount;
609 GSUB_RangeRecord RangeRecord[1];
610 } GSUB_CoverageFormat2;
612 typedef struct {
613 WORD SubstFormat; /* = 1 */
614 WORD Coverage;
615 WORD DeltaGlyphID;
616 } GSUB_SingleSubstFormat1;
618 typedef struct {
619 WORD SubstFormat; /* = 2 */
620 WORD Coverage;
621 WORD GlyphCount;
622 WORD Substitute[1];
623 }GSUB_SingleSubstFormat2;
625 #ifdef HAVE_CARBON_CARBON_H
626 static char *find_cache_dir(void)
628 FSRef ref;
629 OSErr err;
630 static char cached_path[MAX_PATH];
631 static const char *wine = "/Wine", *fonts = "/Fonts";
633 if(*cached_path) return cached_path;
635 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
636 if(err != noErr)
638 WARN("can't create cached data folder\n");
639 return NULL;
641 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
642 if(err != noErr)
644 WARN("can't create cached data path\n");
645 *cached_path = '\0';
646 return NULL;
648 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
650 ERR("Could not create full path\n");
651 *cached_path = '\0';
652 return NULL;
654 strcat(cached_path, wine);
656 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
658 WARN("Couldn't mkdir %s\n", cached_path);
659 *cached_path = '\0';
660 return NULL;
662 strcat(cached_path, fonts);
663 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
665 WARN("Couldn't mkdir %s\n", cached_path);
666 *cached_path = '\0';
667 return NULL;
669 return cached_path;
672 /******************************************************************
673 * expand_mac_font
675 * Extracts individual TrueType font files from a Mac suitcase font
676 * and saves them into the user's caches directory (see
677 * find_cache_dir()).
678 * Returns a NULL terminated array of filenames.
680 * We do this because they are apps that try to read ttf files
681 * themselves and they don't like Mac suitcase files.
683 static char **expand_mac_font(const char *path)
685 FSRef ref;
686 SInt16 res_ref;
687 OSStatus s;
688 unsigned int idx;
689 const char *out_dir;
690 const char *filename;
691 int output_len;
692 struct {
693 char **array;
694 unsigned int size, max_size;
695 } ret;
697 TRACE("path %s\n", path);
699 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
700 if(s != noErr)
702 WARN("failed to get ref\n");
703 return NULL;
706 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
707 if(s != noErr)
709 TRACE("no data fork, so trying resource fork\n");
710 res_ref = FSOpenResFile(&ref, fsRdPerm);
711 if(res_ref == -1)
713 TRACE("unable to open resource fork\n");
714 return NULL;
718 ret.size = 0;
719 ret.max_size = 10;
720 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
721 if(!ret.array)
723 CloseResFile(res_ref);
724 return NULL;
727 out_dir = find_cache_dir();
729 filename = strrchr(path, '/');
730 if(!filename) filename = path;
731 else filename++;
733 /* output filename has the form out_dir/filename_%04x.ttf */
734 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
736 UseResFile(res_ref);
737 idx = 1;
738 while(1)
740 FamRec *fam_rec;
741 unsigned short *num_faces_ptr, num_faces, face;
742 AsscEntry *assoc;
743 Handle fond;
744 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
746 fond = Get1IndResource(fond_res, idx);
747 if(!fond) break;
748 TRACE("got fond resource %d\n", idx);
749 HLock(fond);
751 fam_rec = *(FamRec**)fond;
752 num_faces_ptr = (unsigned short *)(fam_rec + 1);
753 num_faces = GET_BE_WORD(*num_faces_ptr);
754 num_faces++;
755 assoc = (AsscEntry*)(num_faces_ptr + 1);
756 TRACE("num faces %04x\n", num_faces);
757 for(face = 0; face < num_faces; face++, assoc++)
759 Handle sfnt;
760 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
761 unsigned short size, font_id;
762 char *output;
764 size = GET_BE_WORD(assoc->fontSize);
765 font_id = GET_BE_WORD(assoc->fontID);
766 if(size != 0)
768 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
769 continue;
772 TRACE("trying to load sfnt id %04x\n", font_id);
773 sfnt = GetResource(sfnt_res, font_id);
774 if(!sfnt)
776 TRACE("can't get sfnt resource %04x\n", font_id);
777 continue;
780 output = HeapAlloc(GetProcessHeap(), 0, output_len);
781 if(output)
783 int fd;
785 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
787 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
788 if(fd != -1 || errno == EEXIST)
790 if(fd != -1)
792 unsigned char *sfnt_data;
794 HLock(sfnt);
795 sfnt_data = *(unsigned char**)sfnt;
796 write(fd, sfnt_data, GetHandleSize(sfnt));
797 HUnlock(sfnt);
798 close(fd);
800 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
802 ret.max_size *= 2;
803 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
805 ret.array[ret.size++] = output;
807 else
809 WARN("unable to create %s\n", output);
810 HeapFree(GetProcessHeap(), 0, output);
813 ReleaseResource(sfnt);
815 HUnlock(fond);
816 ReleaseResource(fond);
817 idx++;
819 CloseResFile(res_ref);
821 return ret.array;
824 #endif /* HAVE_CARBON_CARBON_H */
826 static inline BOOL is_win9x(void)
828 return GetVersion() & 0x80000000;
831 This function builds an FT_Fixed from a double. It fails if the absolute
832 value of the float number is greater than 32768.
834 static inline FT_Fixed FT_FixedFromFloat(double f)
836 return f * 0x10000;
840 This function builds an FT_Fixed from a FIXED. It simply put f.value
841 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
843 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
845 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
849 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
851 Family *family;
852 Face *face;
853 const char *file;
854 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
855 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
857 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
858 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
860 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
862 if(face_name && strcmpiW(face_name, family->FamilyName))
863 continue;
864 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
866 if (!face->file)
867 continue;
868 file = strrchr(face->file, '/');
869 if(!file)
870 file = face->file;
871 else
872 file++;
873 if(!strcasecmp(file, file_nameA))
875 HeapFree(GetProcessHeap(), 0, file_nameA);
876 return face;
880 HeapFree(GetProcessHeap(), 0, file_nameA);
881 return NULL;
884 static Family *find_family_from_name(const WCHAR *name)
886 Family *family;
888 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
890 if(!strcmpiW(family->FamilyName, name))
891 return family;
894 return NULL;
897 static void DumpSubstList(void)
899 FontSubst *psub;
901 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
903 if(psub->from.charset != -1 || psub->to.charset != -1)
904 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
905 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
906 else
907 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
908 debugstr_w(psub->to.name));
910 return;
913 static LPWSTR strdupW(LPCWSTR p)
915 LPWSTR ret;
916 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
917 ret = HeapAlloc(GetProcessHeap(), 0, len);
918 memcpy(ret, p, len);
919 return ret;
922 static LPSTR strdupA(LPCSTR p)
924 LPSTR ret;
925 DWORD len = (strlen(p) + 1);
926 ret = HeapAlloc(GetProcessHeap(), 0, len);
927 memcpy(ret, p, len);
928 return ret;
931 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
932 INT from_charset)
934 FontSubst *element;
936 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
938 if(!strcmpiW(element->from.name, from_name) &&
939 (element->from.charset == from_charset ||
940 element->from.charset == -1))
941 return element;
944 return NULL;
947 #define ADD_FONT_SUBST_FORCE 1
949 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
951 FontSubst *from_exist, *to_exist;
953 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
955 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
957 list_remove(&from_exist->entry);
958 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
959 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
960 HeapFree(GetProcessHeap(), 0, from_exist);
961 from_exist = NULL;
964 if(!from_exist)
966 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
968 if(to_exist)
970 HeapFree(GetProcessHeap(), 0, subst->to.name);
971 subst->to.name = strdupW(to_exist->to.name);
974 list_add_tail(subst_list, &subst->entry);
976 return TRUE;
979 HeapFree(GetProcessHeap(), 0, subst->from.name);
980 HeapFree(GetProcessHeap(), 0, subst->to.name);
981 HeapFree(GetProcessHeap(), 0, subst);
982 return FALSE;
985 static void split_subst_info(NameCs *nc, LPSTR str)
987 CHAR *p = strrchr(str, ',');
988 DWORD len;
990 nc->charset = -1;
991 if(p && *(p+1)) {
992 nc->charset = strtol(p+1, NULL, 10);
993 *p = '\0';
995 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
996 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
997 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1000 static void LoadSubstList(void)
1002 FontSubst *psub;
1003 HKEY hkey;
1004 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1005 LPSTR value;
1006 LPVOID data;
1008 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1009 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1010 &hkey) == ERROR_SUCCESS) {
1012 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1013 &valuelen, &datalen, NULL, NULL);
1015 valuelen++; /* returned value doesn't include room for '\0' */
1016 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1017 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1019 dlen = datalen;
1020 vlen = valuelen;
1021 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1022 &dlen) == ERROR_SUCCESS) {
1023 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1025 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1026 split_subst_info(&psub->from, value);
1027 split_subst_info(&psub->to, data);
1029 /* Win 2000 doesn't allow mapping between different charsets
1030 or mapping of DEFAULT_CHARSET */
1031 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1032 psub->to.charset == DEFAULT_CHARSET) {
1033 HeapFree(GetProcessHeap(), 0, psub->to.name);
1034 HeapFree(GetProcessHeap(), 0, psub->from.name);
1035 HeapFree(GetProcessHeap(), 0, psub);
1036 } else {
1037 add_font_subst(&font_subst_list, psub, 0);
1039 /* reset dlen and vlen */
1040 dlen = datalen;
1041 vlen = valuelen;
1043 HeapFree(GetProcessHeap(), 0, data);
1044 HeapFree(GetProcessHeap(), 0, value);
1045 RegCloseKey(hkey);
1050 /*****************************************************************
1051 * get_name_table_entry
1053 * Supply the platform, encoding, language and name ids in req
1054 * and if the name exists the function will fill in the string
1055 * and string_len members. The string is owned by FreeType so
1056 * don't free it. Returns TRUE if the name is found else FALSE.
1058 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1060 FT_SfntName name;
1061 FT_UInt num_names, name_index;
1063 if(FT_IS_SFNT(ft_face))
1065 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1067 for(name_index = 0; name_index < num_names; name_index++)
1069 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1071 if((name.platform_id == req->platform_id) &&
1072 (name.encoding_id == req->encoding_id) &&
1073 (name.language_id == req->language_id) &&
1074 (name.name_id == req->name_id))
1076 req->string = name.string;
1077 req->string_len = name.string_len;
1078 return TRUE;
1083 req->string = NULL;
1084 req->string_len = 0;
1085 return FALSE;
1088 static WCHAR *get_familyname(FT_Face ft_face)
1090 WCHAR *family = NULL;
1091 FT_SfntName name;
1093 name.platform_id = TT_PLATFORM_MICROSOFT;
1094 name.encoding_id = TT_MS_ID_UNICODE_CS;
1095 name.language_id = GetUserDefaultLCID();
1096 name.name_id = TT_NAME_ID_FONT_FAMILY;
1098 if(get_name_table_entry(ft_face, &name))
1100 FT_UInt i;
1102 /* String is not nul terminated and string_len is a byte length. */
1103 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1104 for(i = 0; i < name.string_len / 2; i++)
1106 WORD *tmp = (WORD *)&name.string[i * 2];
1107 family[i] = GET_BE_WORD(*tmp);
1109 family[i] = 0;
1110 TRACE("Got localised name %s\n", debugstr_w(family));
1113 return family;
1117 /*****************************************************************
1118 * load_sfnt_table
1120 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1121 * of FreeType that don't export this function.
1124 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1127 FT_Error err;
1129 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1130 if(pFT_Load_Sfnt_Table)
1132 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1134 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1135 else /* Do it the hard way */
1137 TT_Face tt_face = (TT_Face) ft_face;
1138 SFNT_Interface *sfnt;
1139 if (FT_Version.major==2 && FT_Version.minor==0)
1141 /* 2.0.x */
1142 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1144 else
1146 /* A field was added in the middle of the structure in 2.1.x */
1147 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1149 err = sfnt->load_any(tt_face, table, offset, buf, len);
1151 #else
1152 else
1154 static int msg;
1155 if(!msg)
1157 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1158 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1159 "Please upgrade your freetype library.\n");
1160 msg++;
1162 err = FT_Err_Unimplemented_Feature;
1164 #endif
1165 return err;
1168 static inline int TestStyles(DWORD flags, DWORD styles)
1170 return (flags & styles) == styles;
1173 static int StyleOrdering(Face *face)
1175 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1176 return 3;
1177 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1178 return 2;
1179 if (TestStyles(face->ntmFlags, NTM_BOLD))
1180 return 1;
1181 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1182 return 0;
1184 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1185 debugstr_w(face->family->FamilyName),
1186 debugstr_w(face->StyleName),
1187 face->ntmFlags);
1189 return 9999;
1192 /* Add a style of face to a font family using an ordering of the list such
1193 that regular fonts come before bold and italic, and single styles come
1194 before compound styles. */
1195 static void AddFaceToFamily(Face *face, Family *family)
1197 struct list *entry;
1199 LIST_FOR_EACH( entry, &family->faces )
1201 Face *ent = LIST_ENTRY(entry, Face, entry);
1202 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1204 list_add_before( entry, &face->entry );
1207 #define ADDFONT_EXTERNAL_FONT 0x01
1208 #define ADDFONT_FORCE_BITMAP 0x02
1209 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1211 FT_Face ft_face;
1212 TT_OS2 *pOS2;
1213 TT_Header *pHeader = NULL;
1214 WCHAR *english_family, *localised_family, *StyleW;
1215 DWORD len;
1216 Family *family;
1217 Face *face;
1218 struct list *family_elem_ptr, *face_elem_ptr;
1219 FT_Error err;
1220 FT_Long face_index = 0, num_faces;
1221 #ifdef HAVE_FREETYPE_FTWINFNT_H
1222 FT_WinFNT_HeaderRec winfnt_header;
1223 #endif
1224 int i, bitmap_num, internal_leading;
1225 FONTSIGNATURE fs;
1227 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1228 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1230 #ifdef HAVE_CARBON_CARBON_H
1231 if(file && !fake_family)
1233 char **mac_list = expand_mac_font(file);
1234 if(mac_list)
1236 BOOL had_one = FALSE;
1237 char **cursor;
1238 for(cursor = mac_list; *cursor; cursor++)
1240 had_one = TRUE;
1241 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1242 HeapFree(GetProcessHeap(), 0, *cursor);
1244 HeapFree(GetProcessHeap(), 0, mac_list);
1245 if(had_one)
1246 return 1;
1249 #endif /* HAVE_CARBON_CARBON_H */
1251 do {
1252 char *family_name = fake_family;
1254 if (file)
1256 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1257 err = pFT_New_Face(library, file, face_index, &ft_face);
1258 } else
1260 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1261 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1264 if(err != 0) {
1265 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1266 return 0;
1269 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*/
1270 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1271 pFT_Done_Face(ft_face);
1272 return 0;
1275 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1276 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1277 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1278 pFT_Done_Face(ft_face);
1279 return 0;
1282 if(FT_IS_SFNT(ft_face))
1284 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1285 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1286 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1288 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1289 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1290 pFT_Done_Face(ft_face);
1291 return 0;
1294 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1295 we don't want to load these. */
1296 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1298 FT_ULong len = 0;
1300 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1302 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1303 pFT_Done_Face(ft_face);
1304 return 0;
1309 if(!ft_face->family_name || !ft_face->style_name) {
1310 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1311 pFT_Done_Face(ft_face);
1312 return 0;
1315 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1317 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1318 pFT_Done_Face(ft_face);
1319 return 0;
1322 if (target_family)
1324 localised_family = get_familyname(ft_face);
1325 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1327 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1328 HeapFree(GetProcessHeap(), 0, localised_family);
1329 num_faces = ft_face->num_faces;
1330 pFT_Done_Face(ft_face);
1331 continue;
1333 HeapFree(GetProcessHeap(), 0, localised_family);
1336 if(!family_name)
1337 family_name = ft_face->family_name;
1339 bitmap_num = 0;
1340 do {
1341 My_FT_Bitmap_Size *size = NULL;
1342 FT_ULong tmp_size;
1344 if(!FT_IS_SCALABLE(ft_face))
1345 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1347 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1348 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1349 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1351 localised_family = NULL;
1352 if(!fake_family) {
1353 localised_family = get_familyname(ft_face);
1354 if(localised_family && !strcmpiW(localised_family, english_family)) {
1355 HeapFree(GetProcessHeap(), 0, localised_family);
1356 localised_family = NULL;
1360 family = NULL;
1361 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1362 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1363 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1364 break;
1365 family = NULL;
1367 if(!family) {
1368 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1369 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1370 list_init(&family->faces);
1371 list_add_tail(&font_list, &family->entry);
1373 if(localised_family) {
1374 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1375 subst->from.name = strdupW(english_family);
1376 subst->from.charset = -1;
1377 subst->to.name = strdupW(localised_family);
1378 subst->to.charset = -1;
1379 add_font_subst(&font_subst_list, subst, 0);
1382 HeapFree(GetProcessHeap(), 0, localised_family);
1383 HeapFree(GetProcessHeap(), 0, english_family);
1385 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1386 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1387 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1389 internal_leading = 0;
1390 memset(&fs, 0, sizeof(fs));
1392 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1393 if(pOS2) {
1394 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1395 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1396 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1397 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1398 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1399 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1400 if(pOS2->version == 0) {
1401 FT_UInt dummy;
1403 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1404 fs.fsCsb[0] |= FS_LATIN1;
1405 else
1406 fs.fsCsb[0] |= FS_SYMBOL;
1409 #ifdef HAVE_FREETYPE_FTWINFNT_H
1410 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1411 CHARSETINFO csi;
1412 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1413 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1414 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1415 fs = csi.fs;
1416 internal_leading = winfnt_header.internal_leading;
1418 #endif
1420 face_elem_ptr = list_head(&family->faces);
1421 while(face_elem_ptr) {
1422 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1423 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1424 if(!strcmpiW(face->StyleName, StyleW) &&
1425 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1426 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1427 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1428 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1430 if(fake_family) {
1431 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1432 HeapFree(GetProcessHeap(), 0, StyleW);
1433 pFT_Done_Face(ft_face);
1434 return 1;
1436 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1437 TRACE("Original font is newer so skipping this one\n");
1438 HeapFree(GetProcessHeap(), 0, StyleW);
1439 pFT_Done_Face(ft_face);
1440 return 1;
1441 } else {
1442 TRACE("Replacing original with this one\n");
1443 list_remove(&face->entry);
1444 HeapFree(GetProcessHeap(), 0, face->file);
1445 HeapFree(GetProcessHeap(), 0, face->StyleName);
1446 HeapFree(GetProcessHeap(), 0, face);
1447 break;
1451 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1452 face->cached_enum_data = NULL;
1453 face->StyleName = StyleW;
1454 if (file)
1456 face->file = strdupA(file);
1457 face->font_data_ptr = NULL;
1458 face->font_data_size = 0;
1460 else
1462 face->file = NULL;
1463 face->font_data_ptr = font_data_ptr;
1464 face->font_data_size = font_data_size;
1466 face->face_index = face_index;
1467 face->ntmFlags = 0;
1468 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1469 face->ntmFlags |= NTM_ITALIC;
1470 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1471 face->ntmFlags |= NTM_BOLD;
1472 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1473 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1474 face->family = family;
1475 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1476 face->fs = fs;
1477 memset(&face->fs_links, 0, sizeof(face->fs_links));
1479 if(FT_IS_SCALABLE(ft_face)) {
1480 memset(&face->size, 0, sizeof(face->size));
1481 face->scalable = TRUE;
1482 } else {
1483 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1484 size->height, size->width, size->size >> 6,
1485 size->x_ppem >> 6, size->y_ppem >> 6);
1486 face->size.height = size->height;
1487 face->size.width = size->width;
1488 face->size.size = size->size;
1489 face->size.x_ppem = size->x_ppem;
1490 face->size.y_ppem = size->y_ppem;
1491 face->size.internal_leading = internal_leading;
1492 face->scalable = FALSE;
1495 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1496 tmp_size = 0;
1497 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1499 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1500 face->ntmFlags |= NTM_PS_OPENTYPE;
1503 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1504 face->fs.fsCsb[0], face->fs.fsCsb[1],
1505 face->fs.fsUsb[0], face->fs.fsUsb[1],
1506 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1509 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1510 for(i = 0; i < ft_face->num_charmaps; i++) {
1511 switch(ft_face->charmaps[i]->encoding) {
1512 case FT_ENCODING_UNICODE:
1513 case FT_ENCODING_APPLE_ROMAN:
1514 face->fs.fsCsb[0] |= FS_LATIN1;
1515 break;
1516 case FT_ENCODING_MS_SYMBOL:
1517 face->fs.fsCsb[0] |= FS_SYMBOL;
1518 break;
1519 default:
1520 break;
1525 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1526 have_installed_roman_font = TRUE;
1528 AddFaceToFamily(face, family);
1530 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1532 num_faces = ft_face->num_faces;
1533 pFT_Done_Face(ft_face);
1534 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1535 debugstr_w(StyleW));
1536 } while(num_faces > ++face_index);
1537 return num_faces;
1540 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1542 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1545 static void DumpFontList(void)
1547 Family *family;
1548 Face *face;
1549 struct list *family_elem_ptr, *face_elem_ptr;
1551 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1552 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1553 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1554 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1555 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1556 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1557 if(!face->scalable)
1558 TRACE(" %d", face->size.height);
1559 TRACE("\n");
1562 return;
1565 /***********************************************************
1566 * The replacement list is a way to map an entire font
1567 * family onto another family. For example adding
1569 * [HKCU\Software\Wine\Fonts\Replacements]
1570 * "Wingdings"="Winedings"
1572 * would enumerate the Winedings font both as Winedings and
1573 * Wingdings. However if a real Wingdings font is present the
1574 * replacement does not take place.
1577 static void LoadReplaceList(void)
1579 HKEY hkey;
1580 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1581 LPWSTR value;
1582 LPVOID data;
1583 Family *family;
1584 Face *face;
1585 struct list *family_elem_ptr, *face_elem_ptr;
1586 CHAR familyA[400];
1588 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1589 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1591 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1592 &valuelen, &datalen, NULL, NULL);
1594 valuelen++; /* returned value doesn't include room for '\0' */
1595 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1596 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1598 dlen = datalen;
1599 vlen = valuelen;
1600 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1601 &dlen) == ERROR_SUCCESS) {
1602 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1603 /* "NewName"="Oldname" */
1604 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1606 /* Find the old family and hence all of the font files
1607 in that family */
1608 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1609 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1610 if(!strcmpiW(family->FamilyName, data)) {
1611 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1612 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1613 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1614 debugstr_w(face->StyleName), familyA);
1615 /* Now add a new entry with the new family name */
1616 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1618 break;
1621 /* reset dlen and vlen */
1622 dlen = datalen;
1623 vlen = valuelen;
1625 HeapFree(GetProcessHeap(), 0, data);
1626 HeapFree(GetProcessHeap(), 0, value);
1627 RegCloseKey(hkey);
1631 /*************************************************************
1632 * init_system_links
1634 static BOOL init_system_links(void)
1636 HKEY hkey;
1637 BOOL ret = FALSE;
1638 DWORD type, max_val, max_data, val_len, data_len, index;
1639 WCHAR *value, *data;
1640 WCHAR *entry, *next;
1641 SYSTEM_LINKS *font_link, *system_font_link;
1642 CHILD_FONT *child_font;
1643 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1644 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1645 FONTSIGNATURE fs;
1646 Family *family;
1647 Face *face;
1648 FontSubst *psub;
1650 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1652 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1653 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1654 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1655 val_len = max_val + 1;
1656 data_len = max_data;
1657 index = 0;
1658 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1660 memset(&fs, 0, sizeof(fs));
1661 psub = get_font_subst(&font_subst_list, value, -1);
1662 /* Don't store fonts that are only substitutes for other fonts */
1663 if(psub)
1665 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1666 goto next;
1668 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1669 font_link->font_name = strdupW(value);
1670 list_init(&font_link->links);
1671 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1673 WCHAR *face_name;
1674 CHILD_FONT *child_font;
1676 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1678 next = entry + strlenW(entry) + 1;
1680 face_name = strchrW(entry, ',');
1681 if(face_name)
1683 *face_name++ = 0;
1684 while(isspaceW(*face_name))
1685 face_name++;
1687 psub = get_font_subst(&font_subst_list, face_name, -1);
1688 if(psub)
1689 face_name = psub->to.name;
1691 face = find_face_from_filename(entry, face_name);
1692 if(!face)
1694 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1695 continue;
1698 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1699 child_font->face = face;
1700 child_font->font = NULL;
1701 fs.fsCsb[0] |= face->fs.fsCsb[0];
1702 fs.fsCsb[1] |= face->fs.fsCsb[1];
1703 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1704 list_add_tail(&font_link->links, &child_font->entry);
1706 family = find_family_from_name(font_link->font_name);
1707 if(family)
1709 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1711 face->fs_links = fs;
1714 list_add_tail(&system_links, &font_link->entry);
1715 next:
1716 val_len = max_val + 1;
1717 data_len = max_data;
1720 HeapFree(GetProcessHeap(), 0, value);
1721 HeapFree(GetProcessHeap(), 0, data);
1722 RegCloseKey(hkey);
1725 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1726 that Tahoma has */
1728 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1729 system_font_link->font_name = strdupW(System);
1730 list_init(&system_font_link->links);
1732 face = find_face_from_filename(tahoma_ttf, Tahoma);
1733 if(face)
1735 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1736 child_font->face = face;
1737 child_font->font = NULL;
1738 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1739 list_add_tail(&system_font_link->links, &child_font->entry);
1741 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1743 if(!strcmpiW(font_link->font_name, Tahoma))
1745 CHILD_FONT *font_link_entry;
1746 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1748 CHILD_FONT *new_child;
1749 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1750 new_child->face = font_link_entry->face;
1751 new_child->font = NULL;
1752 list_add_tail(&system_font_link->links, &new_child->entry);
1754 break;
1757 list_add_tail(&system_links, &system_font_link->entry);
1758 return ret;
1761 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1763 DIR *dir;
1764 struct dirent *dent;
1765 char path[MAX_PATH];
1767 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1769 dir = opendir(dirname);
1770 if(!dir) {
1771 WARN("Can't open directory %s\n", debugstr_a(dirname));
1772 return FALSE;
1774 while((dent = readdir(dir)) != NULL) {
1775 struct stat statbuf;
1777 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1778 continue;
1780 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1782 sprintf(path, "%s/%s", dirname, dent->d_name);
1784 if(stat(path, &statbuf) == -1)
1786 WARN("Can't stat %s\n", debugstr_a(path));
1787 continue;
1789 if(S_ISDIR(statbuf.st_mode))
1790 ReadFontDir(path, external_fonts);
1791 else
1792 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1794 closedir(dir);
1795 return TRUE;
1798 static void load_fontconfig_fonts(void)
1800 #ifdef SONAME_LIBFONTCONFIG
1801 void *fc_handle = NULL;
1802 FcConfig *config;
1803 FcPattern *pat;
1804 FcObjectSet *os;
1805 FcFontSet *fontset;
1806 int i, len;
1807 char *file;
1808 const char *ext;
1810 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1811 if(!fc_handle) {
1812 TRACE("Wine cannot find the fontconfig library (%s).\n",
1813 SONAME_LIBFONTCONFIG);
1814 return;
1816 #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;}
1817 LOAD_FUNCPTR(FcConfigGetCurrent);
1818 LOAD_FUNCPTR(FcFontList);
1819 LOAD_FUNCPTR(FcFontSetDestroy);
1820 LOAD_FUNCPTR(FcInit);
1821 LOAD_FUNCPTR(FcObjectSetAdd);
1822 LOAD_FUNCPTR(FcObjectSetCreate);
1823 LOAD_FUNCPTR(FcObjectSetDestroy);
1824 LOAD_FUNCPTR(FcPatternCreate);
1825 LOAD_FUNCPTR(FcPatternDestroy);
1826 LOAD_FUNCPTR(FcPatternGetBool);
1827 LOAD_FUNCPTR(FcPatternGetString);
1828 #undef LOAD_FUNCPTR
1830 if(!pFcInit()) return;
1832 config = pFcConfigGetCurrent();
1833 pat = pFcPatternCreate();
1834 os = pFcObjectSetCreate();
1835 pFcObjectSetAdd(os, FC_FILE);
1836 pFcObjectSetAdd(os, FC_SCALABLE);
1837 fontset = pFcFontList(config, pat, os);
1838 if(!fontset) return;
1839 for(i = 0; i < fontset->nfont; i++) {
1840 FcBool scalable;
1842 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1843 continue;
1844 TRACE("fontconfig: %s\n", file);
1846 /* We're just interested in OT/TT fonts for now, so this hack just
1847 picks up the scalable fonts without extensions .pf[ab] to save time
1848 loading every other font */
1850 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1852 TRACE("not scalable\n");
1853 continue;
1856 len = strlen( file );
1857 if(len < 4) continue;
1858 ext = &file[ len - 3 ];
1859 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1860 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1862 pFcFontSetDestroy(fontset);
1863 pFcObjectSetDestroy(os);
1864 pFcPatternDestroy(pat);
1865 sym_not_found:
1866 #endif
1867 return;
1870 static BOOL load_font_from_data_dir(LPCWSTR file)
1872 BOOL ret = FALSE;
1873 const char *data_dir = wine_get_data_dir();
1875 if (!data_dir) data_dir = wine_get_build_dir();
1877 if (data_dir)
1879 INT len;
1880 char *unix_name;
1882 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1884 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1886 strcpy(unix_name, data_dir);
1887 strcat(unix_name, "/fonts/");
1889 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1891 EnterCriticalSection( &freetype_cs );
1892 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1893 LeaveCriticalSection( &freetype_cs );
1894 HeapFree(GetProcessHeap(), 0, unix_name);
1896 return ret;
1899 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1901 static const WCHAR slashW[] = {'\\','\0'};
1902 BOOL ret = FALSE;
1903 WCHAR windowsdir[MAX_PATH];
1904 char *unixname;
1906 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1907 strcatW(windowsdir, fontsW);
1908 strcatW(windowsdir, slashW);
1909 strcatW(windowsdir, file);
1910 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1911 EnterCriticalSection( &freetype_cs );
1912 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1913 LeaveCriticalSection( &freetype_cs );
1914 HeapFree(GetProcessHeap(), 0, unixname);
1916 return ret;
1919 static void load_system_fonts(void)
1921 HKEY hkey;
1922 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1923 const WCHAR * const *value;
1924 DWORD dlen, type;
1925 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1926 char *unixname;
1928 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1929 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1930 strcatW(windowsdir, fontsW);
1931 for(value = SystemFontValues; *value; value++) {
1932 dlen = sizeof(data);
1933 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1934 type == REG_SZ) {
1935 BOOL added = FALSE;
1937 sprintfW(pathW, fmtW, windowsdir, data);
1938 if((unixname = wine_get_unix_file_name(pathW))) {
1939 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1940 HeapFree(GetProcessHeap(), 0, unixname);
1942 if (!added)
1943 load_font_from_data_dir(data);
1946 RegCloseKey(hkey);
1950 /*************************************************************
1952 * This adds registry entries for any externally loaded fonts
1953 * (fonts from fontconfig or FontDirs). It also deletes entries
1954 * of no longer existing fonts.
1957 static void update_reg_entries(void)
1959 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1960 LPWSTR valueW;
1961 DWORD len, len_fam;
1962 Family *family;
1963 Face *face;
1964 struct list *family_elem_ptr, *face_elem_ptr;
1965 WCHAR *file;
1966 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1967 static const WCHAR spaceW[] = {' ', '\0'};
1968 char *path;
1970 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1971 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1972 ERR("Can't create Windows font reg key\n");
1973 goto end;
1976 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1977 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1978 ERR("Can't create Windows font reg key\n");
1979 goto end;
1982 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1983 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1984 ERR("Can't create external font reg key\n");
1985 goto end;
1988 /* enumerate the fonts and add external ones to the two keys */
1990 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1991 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1992 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1993 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1994 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1995 if(!face->external) continue;
1996 len = len_fam;
1997 if (!(face->ntmFlags & NTM_REGULAR))
1998 len = len_fam + strlenW(face->StyleName) + 1;
1999 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2000 strcpyW(valueW, family->FamilyName);
2001 if(len != len_fam) {
2002 strcatW(valueW, spaceW);
2003 strcatW(valueW, face->StyleName);
2005 strcatW(valueW, TrueType);
2007 file = wine_get_dos_file_name(face->file);
2008 if(file)
2009 len = strlenW(file) + 1;
2010 else
2012 if((path = strrchr(face->file, '/')) == NULL)
2013 path = face->file;
2014 else
2015 path++;
2016 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2018 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2019 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2021 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2022 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2023 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2025 HeapFree(GetProcessHeap(), 0, file);
2026 HeapFree(GetProcessHeap(), 0, valueW);
2029 end:
2030 if(external_key) RegCloseKey(external_key);
2031 if(win9x_key) RegCloseKey(win9x_key);
2032 if(winnt_key) RegCloseKey(winnt_key);
2033 return;
2036 static void delete_external_font_keys(void)
2038 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2039 DWORD dlen, vlen, datalen, valuelen, i, type;
2040 LPWSTR valueW;
2041 LPVOID data;
2043 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2044 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2045 ERR("Can't create Windows font reg key\n");
2046 goto end;
2049 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2050 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2051 ERR("Can't create Windows font reg key\n");
2052 goto end;
2055 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2056 ERR("Can't create external font reg key\n");
2057 goto end;
2060 /* Delete all external fonts added last time */
2062 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2063 &valuelen, &datalen, NULL, NULL);
2064 valuelen++; /* returned value doesn't include room for '\0' */
2065 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2066 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2068 dlen = datalen * sizeof(WCHAR);
2069 vlen = valuelen;
2070 i = 0;
2071 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2072 &dlen) == ERROR_SUCCESS) {
2074 RegDeleteValueW(winnt_key, valueW);
2075 RegDeleteValueW(win9x_key, valueW);
2076 /* reset dlen and vlen */
2077 dlen = datalen;
2078 vlen = valuelen;
2080 HeapFree(GetProcessHeap(), 0, data);
2081 HeapFree(GetProcessHeap(), 0, valueW);
2083 /* Delete the old external fonts key */
2084 RegCloseKey(external_key);
2085 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2087 end:
2088 if(win9x_key) RegCloseKey(win9x_key);
2089 if(winnt_key) RegCloseKey(winnt_key);
2092 /*************************************************************
2093 * WineEngAddFontResourceEx
2096 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2098 INT ret = 0;
2100 GDI_CheckNotLock();
2102 if (ft_handle) /* do it only if we have freetype up and running */
2104 char *unixname;
2106 if(flags)
2107 FIXME("Ignoring flags %x\n", flags);
2109 if((unixname = wine_get_unix_file_name(file)))
2111 EnterCriticalSection( &freetype_cs );
2112 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2113 LeaveCriticalSection( &freetype_cs );
2114 HeapFree(GetProcessHeap(), 0, unixname);
2116 if (!ret && !strchrW(file, '\\')) {
2117 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2118 ret = load_font_from_winfonts_dir(file);
2119 if (!ret) {
2120 /* Try in datadir/fonts (or builddir/fonts),
2121 * needed for Magic the Gathering Online
2123 ret = load_font_from_data_dir(file);
2127 return ret;
2130 /*************************************************************
2131 * WineEngAddFontMemResourceEx
2134 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2136 GDI_CheckNotLock();
2138 if (ft_handle) /* do it only if we have freetype up and running */
2140 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2142 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2143 memcpy(pFontCopy, pbFont, cbFont);
2145 EnterCriticalSection( &freetype_cs );
2146 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2147 LeaveCriticalSection( &freetype_cs );
2149 if (*pcFonts == 0)
2151 TRACE("AddFontToList failed\n");
2152 HeapFree(GetProcessHeap(), 0, pFontCopy);
2153 return NULL;
2155 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2156 * For now return something unique but quite random
2158 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2159 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2162 *pcFonts = 0;
2163 return 0;
2166 /*************************************************************
2167 * WineEngRemoveFontResourceEx
2170 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2172 GDI_CheckNotLock();
2173 FIXME(":stub\n");
2174 return TRUE;
2177 static const struct nls_update_font_list
2179 UINT ansi_cp, oem_cp;
2180 const char *oem, *fixed, *system;
2181 const char *courier, *serif, *small, *sserif;
2182 /* these are for font substitutes */
2183 const char *shelldlg, *tmsrmn;
2184 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2185 *helv_0, *tmsrmn_0;
2186 const struct subst
2188 const char *from, *to;
2189 } arial_0, courier_new_0, times_new_roman_0;
2190 } nls_update_font_list[] =
2192 /* Latin 1 (United States) */
2193 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2194 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2195 "Tahoma","Times New Roman",
2196 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2197 { 0 }, { 0 }, { 0 }
2199 /* Latin 1 (Multilingual) */
2200 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "Tahoma","Times New Roman", /* FIXME unverified */
2203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2204 { 0 }, { 0 }, { 0 }
2206 /* Eastern Europe */
2207 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2208 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 "Fixedsys,238", "System,238",
2211 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2212 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2213 { "Arial CE,0", "Arial,238" },
2214 { "Courier New CE,0", "Courier New,238" },
2215 { "Times New Roman CE,0", "Times New Roman,238" }
2217 /* Cyrillic */
2218 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2219 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2220 "Tahoma","Times New Roman", /* FIXME unverified */
2221 "Fixedsys,204", "System,204",
2222 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2223 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2224 { "Arial Cyr,0", "Arial,204" },
2225 { "Courier New Cyr,0", "Courier New,204" },
2226 { "Times New Roman Cyr,0", "Times New Roman,204" }
2228 /* Greek */
2229 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2230 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2231 "Tahoma","Times New Roman", /* FIXME unverified */
2232 "Fixedsys,161", "System,161",
2233 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2234 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2235 { "Arial Greek,0", "Arial,161" },
2236 { "Courier New Greek,0", "Courier New,161" },
2237 { "Times New Roman Greek,0", "Times New Roman,161" }
2239 /* Turkish */
2240 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2241 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2242 "Tahoma","Times New Roman", /* FIXME unverified */
2243 "Fixedsys,162", "System,162",
2244 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2245 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2246 { "Arial Tur,0", "Arial,162" },
2247 { "Courier New Tur,0", "Courier New,162" },
2248 { "Times New Roman Tur,0", "Times New Roman,162" }
2250 /* Hebrew */
2251 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2252 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2253 "Tahoma","Times New Roman", /* FIXME unverified */
2254 "Fixedsys,177", "System,177",
2255 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2256 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2257 { 0 }, { 0 }, { 0 }
2259 /* Arabic */
2260 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2261 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2262 "Tahoma","Times New Roman", /* FIXME unverified */
2263 "Fixedsys,178", "System,178",
2264 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2265 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2266 { 0 }, { 0 }, { 0 }
2268 /* Baltic */
2269 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2270 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2271 "Tahoma","Times New Roman", /* FIXME unverified */
2272 "Fixedsys,186", "System,186",
2273 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2274 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2275 { "Arial Baltic,0", "Arial,186" },
2276 { "Courier New Baltic,0", "Courier New,186" },
2277 { "Times New Roman Baltic,0", "Times New Roman,186" }
2279 /* Vietnamese */
2280 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2281 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2282 "Tahoma","Times New Roman", /* FIXME unverified */
2283 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2284 { 0 }, { 0 }, { 0 }
2286 /* Thai */
2287 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2288 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2289 "Tahoma","Times New Roman", /* FIXME unverified */
2290 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2291 { 0 }, { 0 }, { 0 }
2293 /* Japanese */
2294 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2295 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2296 "MS UI Gothic","MS Serif",
2297 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2298 { 0 }, { 0 }, { 0 }
2300 /* Chinese Simplified */
2301 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2302 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2303 "SimSun", "NSimSun",
2304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2305 { 0 }, { 0 }, { 0 }
2307 /* Korean */
2308 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2309 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2310 "Gulim", "Batang",
2311 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2312 { 0 }, { 0 }, { 0 }
2314 /* Chinese Traditional */
2315 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2316 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2317 "PMingLiU", "MingLiU",
2318 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2319 { 0 }, { 0 }, { 0 }
2323 static const WCHAR *font_links_list[] =
2325 Lucida_Sans_Unicode,
2326 Microsoft_Sans_Serif,
2327 Tahoma
2330 static const struct font_links_defaults_list
2332 /* Keyed off substitution for "MS Shell Dlg" */
2333 const WCHAR *shelldlg;
2334 /* Maximum of four substitutes, plus terminating NULL pointer */
2335 const WCHAR *substitutes[5];
2336 } font_links_defaults_list[] =
2338 /* Non East-Asian */
2339 { Tahoma, /* FIXME unverified ordering */
2340 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2342 /* Below lists are courtesy of
2343 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2345 /* Japanese */
2346 { MS_UI_Gothic,
2347 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2349 /* Chinese Simplified */
2350 { SimSun,
2351 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2353 /* Korean */
2354 { Gulim,
2355 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2357 /* Chinese Traditional */
2358 { PMingLiU,
2359 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2363 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2365 return ( ansi_cp == 932 /* CP932 for Japanese */
2366 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2367 || ansi_cp == 949 /* CP949 for Korean */
2368 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2371 static inline HKEY create_fonts_NT_registry_key(void)
2373 HKEY hkey = 0;
2375 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2376 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2377 return hkey;
2380 static inline HKEY create_fonts_9x_registry_key(void)
2382 HKEY hkey = 0;
2384 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2385 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2386 return hkey;
2389 static inline HKEY create_config_fonts_registry_key(void)
2391 HKEY hkey = 0;
2393 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2394 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2395 return hkey;
2398 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2400 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2401 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2402 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2403 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2406 static void set_value_key(HKEY hkey, const char *name, const char *value)
2408 if (value)
2409 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2410 else if (name)
2411 RegDeleteValueA(hkey, name);
2414 static void update_font_info(void)
2416 char buf[40], cpbuf[40];
2417 DWORD len, type;
2418 HKEY hkey = 0;
2419 UINT i, ansi_cp = 0, oem_cp = 0;
2420 BOOL done = FALSE;
2422 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2423 return;
2425 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2426 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2427 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2428 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2429 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2431 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2432 if (is_dbcs_ansi_cp(ansi_cp))
2433 use_default_fallback = TRUE;
2435 len = sizeof(buf);
2436 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2438 if (!strcmp( buf, cpbuf )) /* already set correctly */
2440 RegCloseKey(hkey);
2441 return;
2443 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2445 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2447 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2448 RegCloseKey(hkey);
2450 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2452 HKEY hkey;
2454 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2455 nls_update_font_list[i].oem_cp == oem_cp)
2457 hkey = create_config_fonts_registry_key();
2458 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2459 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2460 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2461 RegCloseKey(hkey);
2463 hkey = create_fonts_NT_registry_key();
2464 add_font_list(hkey, &nls_update_font_list[i]);
2465 RegCloseKey(hkey);
2467 hkey = create_fonts_9x_registry_key();
2468 add_font_list(hkey, &nls_update_font_list[i]);
2469 RegCloseKey(hkey);
2471 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2473 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2474 strlen(nls_update_font_list[i].shelldlg)+1);
2475 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2476 strlen(nls_update_font_list[i].tmsrmn)+1);
2478 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2479 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2480 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2481 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2482 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2483 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2484 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2485 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2487 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2488 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2489 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2491 RegCloseKey(hkey);
2493 done = TRUE;
2495 else
2497 /* Delete the FontSubstitutes from other locales */
2498 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2500 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2501 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2502 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2503 RegCloseKey(hkey);
2507 if (!done)
2508 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2510 /* Clear out system links */
2511 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2514 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2516 const WCHAR *value;
2517 int i;
2518 FontSubst *psub;
2519 Family *family;
2520 Face *face;
2521 const char *file;
2522 WCHAR *fileW;
2523 int fileLen;
2524 WCHAR buff[MAX_PATH];
2525 WCHAR *data;
2526 int entryLen;
2528 static const WCHAR comma[] = {',',0};
2530 RegDeleteValueW(hkey, name);
2531 if (values)
2533 data = buff;
2534 data[0] = '\0';
2535 for (i = 0; values[i] != NULL; i++)
2537 value = values[i];
2538 if (!strcmpiW(name,value))
2539 continue;
2540 psub = get_font_subst(&font_subst_list, value, -1);
2541 if(psub)
2542 value = psub->to.name;
2543 family = find_family_from_name(value);
2544 if (!family)
2545 continue;
2546 file = NULL;
2547 /* Use first extant filename for this Family */
2548 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2550 if (!face->file)
2551 continue;
2552 file = strrchr(face->file, '/');
2553 if (!file)
2554 file = face->file;
2555 else
2556 file++;
2557 break;
2559 if (!file)
2560 continue;
2561 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2562 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2563 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2564 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2565 if (sizeof(buff)-(data-buff) < entryLen + 1)
2567 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2568 HeapFree(GetProcessHeap(), 0, fileW);
2569 break;
2571 strcpyW(data, fileW);
2572 strcatW(data, comma);
2573 strcatW(data, value);
2574 data += entryLen;
2575 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2576 HeapFree(GetProcessHeap(), 0, fileW);
2578 if (data != buff)
2580 *data='\0';
2581 data++;
2582 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2583 } else
2584 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2585 } else
2586 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2589 static void update_system_links(void)
2591 HKEY hkey = 0;
2592 UINT i, j;
2593 BOOL done = FALSE;
2594 DWORD disposition;
2595 FontSubst *psub;
2597 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2599 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2601 if (disposition == REG_OPENED_EXISTING_KEY)
2603 TRACE("SystemLink key already exists, doing nothing\n");
2604 RegCloseKey(hkey);
2605 return;
2608 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2609 if (!psub) {
2610 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2611 RegCloseKey(hkey);
2612 return;
2615 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2617 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2619 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2620 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2622 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2623 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2624 done = TRUE;
2626 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2628 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2631 RegCloseKey(hkey);
2632 if (!done)
2633 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2634 } else
2635 WARN("failed to create SystemLink key\n");
2639 static BOOL init_freetype(void)
2641 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2642 if(!ft_handle) {
2643 WINE_MESSAGE(
2644 "Wine cannot find the FreeType font library. To enable Wine to\n"
2645 "use TrueType fonts please install a version of FreeType greater than\n"
2646 "or equal to 2.0.5.\n"
2647 "http://www.freetype.org\n");
2648 return FALSE;
2651 #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;}
2653 LOAD_FUNCPTR(FT_Vector_Unit)
2654 LOAD_FUNCPTR(FT_Done_Face)
2655 LOAD_FUNCPTR(FT_Get_Char_Index)
2656 LOAD_FUNCPTR(FT_Get_Module)
2657 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2658 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2659 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2660 LOAD_FUNCPTR(FT_Init_FreeType)
2661 LOAD_FUNCPTR(FT_Load_Glyph)
2662 LOAD_FUNCPTR(FT_Matrix_Multiply)
2663 #ifndef FT_MULFIX_INLINED
2664 LOAD_FUNCPTR(FT_MulFix)
2665 #endif
2666 LOAD_FUNCPTR(FT_New_Face)
2667 LOAD_FUNCPTR(FT_New_Memory_Face)
2668 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2669 LOAD_FUNCPTR(FT_Outline_Transform)
2670 LOAD_FUNCPTR(FT_Outline_Translate)
2671 LOAD_FUNCPTR(FT_Select_Charmap)
2672 LOAD_FUNCPTR(FT_Set_Charmap)
2673 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2674 LOAD_FUNCPTR(FT_Vector_Transform)
2675 LOAD_FUNCPTR(FT_Render_Glyph)
2677 #undef LOAD_FUNCPTR
2678 /* Don't warn if these ones are missing */
2679 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2680 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2681 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2682 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2683 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2684 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2685 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2686 #endif
2687 #ifdef HAVE_FREETYPE_FTWINFNT_H
2688 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2689 #endif
2690 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2691 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2692 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2693 <= 2.0.3 has FT_Sqrt64 */
2694 goto sym_not_found;
2697 if(pFT_Init_FreeType(&library) != 0) {
2698 ERR("Can't init FreeType library\n");
2699 wine_dlclose(ft_handle, NULL, 0);
2700 ft_handle = NULL;
2701 return FALSE;
2703 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2704 if (pFT_Library_Version)
2705 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2707 if (FT_Version.major<=0)
2709 FT_Version.major=2;
2710 FT_Version.minor=0;
2711 FT_Version.patch=5;
2713 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2714 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2715 ((FT_Version.minor << 8) & 0x00ff00) |
2716 ((FT_Version.patch ) & 0x0000ff);
2718 return TRUE;
2720 sym_not_found:
2721 WINE_MESSAGE(
2722 "Wine cannot find certain functions that it needs inside the FreeType\n"
2723 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2724 "FreeType to at least version 2.0.5.\n"
2725 "http://www.freetype.org\n");
2726 wine_dlclose(ft_handle, NULL, 0);
2727 ft_handle = NULL;
2728 return FALSE;
2731 /*************************************************************
2732 * WineEngInit
2734 * Initialize FreeType library and create a list of available faces
2736 BOOL WineEngInit(void)
2738 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2739 static const WCHAR pathW[] = {'P','a','t','h',0};
2740 HKEY hkey;
2741 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2742 WCHAR windowsdir[MAX_PATH];
2743 char *unixname;
2744 HANDLE font_mutex;
2745 const char *data_dir;
2747 TRACE("\n");
2749 /* update locale dependent font info in registry */
2750 update_font_info();
2752 if(!init_freetype()) return FALSE;
2754 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2755 ERR("Failed to create font mutex\n");
2756 return FALSE;
2758 WaitForSingleObject(font_mutex, INFINITE);
2760 delete_external_font_keys();
2762 /* load the system bitmap fonts */
2763 load_system_fonts();
2765 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2766 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2767 strcatW(windowsdir, fontsW);
2768 if((unixname = wine_get_unix_file_name(windowsdir)))
2770 ReadFontDir(unixname, FALSE);
2771 HeapFree(GetProcessHeap(), 0, unixname);
2774 /* load the system truetype fonts */
2775 data_dir = wine_get_data_dir();
2776 if (!data_dir) data_dir = wine_get_build_dir();
2777 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2778 strcpy(unixname, data_dir);
2779 strcat(unixname, "/fonts/");
2780 ReadFontDir(unixname, TRUE);
2781 HeapFree(GetProcessHeap(), 0, unixname);
2784 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2785 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2786 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2787 will skip these. */
2788 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2789 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2790 &hkey) == ERROR_SUCCESS) {
2791 LPWSTR data, valueW;
2792 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2793 &valuelen, &datalen, NULL, NULL);
2795 valuelen++; /* returned value doesn't include room for '\0' */
2796 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2797 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2798 if (valueW && data)
2800 dlen = datalen * sizeof(WCHAR);
2801 vlen = valuelen;
2802 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2803 &dlen) == ERROR_SUCCESS) {
2804 if(data[0] && (data[1] == ':'))
2806 if((unixname = wine_get_unix_file_name(data)))
2808 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2809 HeapFree(GetProcessHeap(), 0, unixname);
2812 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2814 WCHAR pathW[MAX_PATH];
2815 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2816 BOOL added = FALSE;
2818 sprintfW(pathW, fmtW, windowsdir, data);
2819 if((unixname = wine_get_unix_file_name(pathW)))
2821 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2822 HeapFree(GetProcessHeap(), 0, unixname);
2824 if (!added)
2825 load_font_from_data_dir(data);
2827 /* reset dlen and vlen */
2828 dlen = datalen;
2829 vlen = valuelen;
2832 HeapFree(GetProcessHeap(), 0, data);
2833 HeapFree(GetProcessHeap(), 0, valueW);
2834 RegCloseKey(hkey);
2837 load_fontconfig_fonts();
2839 /* then look in any directories that we've specified in the config file */
2840 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2841 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2843 DWORD len;
2844 LPWSTR valueW;
2845 LPSTR valueA, ptr;
2847 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2849 len += sizeof(WCHAR);
2850 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2851 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2853 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2854 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2855 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2856 TRACE( "got font path %s\n", debugstr_a(valueA) );
2857 ptr = valueA;
2858 while (ptr)
2860 LPSTR next = strchr( ptr, ':' );
2861 if (next) *next++ = 0;
2862 ReadFontDir( ptr, TRUE );
2863 ptr = next;
2865 HeapFree( GetProcessHeap(), 0, valueA );
2867 HeapFree( GetProcessHeap(), 0, valueW );
2869 RegCloseKey(hkey);
2872 DumpFontList();
2873 LoadSubstList();
2874 DumpSubstList();
2875 LoadReplaceList();
2876 update_reg_entries();
2878 update_system_links();
2879 init_system_links();
2881 ReleaseMutex(font_mutex);
2882 return TRUE;
2886 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2888 TT_OS2 *pOS2;
2889 TT_HoriHeader *pHori;
2891 LONG ppem;
2893 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2894 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2896 if(height == 0) height = 16;
2898 /* Calc. height of EM square:
2900 * For +ve lfHeight we have
2901 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2902 * Re-arranging gives:
2903 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2905 * For -ve lfHeight we have
2906 * |lfHeight| = ppem
2907 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2908 * with il = winAscent + winDescent - units_per_em]
2912 if(height > 0) {
2913 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2914 ppem = MulDiv(ft_face->units_per_EM, height,
2915 pHori->Ascender - pHori->Descender);
2916 else
2917 ppem = MulDiv(ft_face->units_per_EM, height,
2918 pOS2->usWinAscent + pOS2->usWinDescent);
2920 else
2921 ppem = -height;
2923 return ppem;
2926 static struct font_mapping *map_font_file( const char *name )
2928 struct font_mapping *mapping;
2929 struct stat st;
2930 int fd;
2932 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2933 if (fstat( fd, &st ) == -1) goto error;
2935 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2937 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2939 mapping->refcount++;
2940 close( fd );
2941 return mapping;
2944 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2945 goto error;
2947 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2948 close( fd );
2950 if (mapping->data == MAP_FAILED)
2952 HeapFree( GetProcessHeap(), 0, mapping );
2953 return NULL;
2955 mapping->refcount = 1;
2956 mapping->dev = st.st_dev;
2957 mapping->ino = st.st_ino;
2958 mapping->size = st.st_size;
2959 list_add_tail( &mappings_list, &mapping->entry );
2960 return mapping;
2962 error:
2963 close( fd );
2964 return NULL;
2967 static void unmap_font_file( struct font_mapping *mapping )
2969 if (!--mapping->refcount)
2971 list_remove( &mapping->entry );
2972 munmap( mapping->data, mapping->size );
2973 HeapFree( GetProcessHeap(), 0, mapping );
2977 static LONG load_VDMX(GdiFont*, LONG);
2979 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2981 FT_Error err;
2982 FT_Face ft_face;
2983 void *data_ptr;
2984 DWORD data_size;
2986 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2988 if (face->file)
2990 if (!(font->mapping = map_font_file( face->file )))
2992 WARN("failed to map %s\n", debugstr_a(face->file));
2993 return 0;
2995 data_ptr = font->mapping->data;
2996 data_size = font->mapping->size;
2998 else
3000 data_ptr = face->font_data_ptr;
3001 data_size = face->font_data_size;
3004 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3005 if(err) {
3006 ERR("FT_New_Face rets %d\n", err);
3007 return 0;
3010 /* set it here, as load_VDMX needs it */
3011 font->ft_face = ft_face;
3013 if(FT_IS_SCALABLE(ft_face)) {
3014 /* load the VDMX table if we have one */
3015 font->ppem = load_VDMX(font, height);
3016 if(font->ppem == 0)
3017 font->ppem = calc_ppem_for_height(ft_face, height);
3018 TRACE("height %d => ppem %d\n", height, font->ppem);
3020 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3021 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3022 } else {
3023 font->ppem = height;
3024 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3025 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3027 return ft_face;
3031 static int get_nearest_charset(Face *face, int *cp)
3033 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3034 a single face with the requested charset. The idea is to check if
3035 the selected font supports the current ANSI codepage, if it does
3036 return the corresponding charset, else return the first charset */
3038 CHARSETINFO csi;
3039 int acp = GetACP(), i;
3040 DWORD fs0;
3042 *cp = acp;
3043 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3044 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3045 return csi.ciCharset;
3047 for(i = 0; i < 32; i++) {
3048 fs0 = 1L << i;
3049 if(face->fs.fsCsb[0] & fs0) {
3050 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3051 *cp = csi.ciACP;
3052 return csi.ciCharset;
3054 else
3055 FIXME("TCI failing on %x\n", fs0);
3059 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3060 face->fs.fsCsb[0], face->file);
3061 *cp = acp;
3062 return DEFAULT_CHARSET;
3065 static GdiFont *alloc_font(void)
3067 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3068 ret->gmsize = 1;
3069 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3070 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3071 ret->potm = NULL;
3072 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3073 ret->total_kern_pairs = (DWORD)-1;
3074 ret->kern_pairs = NULL;
3075 list_init(&ret->hfontlist);
3076 list_init(&ret->child_fonts);
3077 return ret;
3080 static void free_font(GdiFont *font)
3082 struct list *cursor, *cursor2;
3083 DWORD i;
3085 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3087 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3088 struct list *first_hfont;
3089 HFONTLIST *hfontlist;
3090 list_remove(cursor);
3091 if(child->font)
3093 first_hfont = list_head(&child->font->hfontlist);
3094 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3095 DeleteObject(hfontlist->hfont);
3096 HeapFree(GetProcessHeap(), 0, hfontlist);
3097 free_font(child->font);
3099 HeapFree(GetProcessHeap(), 0, child);
3102 if (font->ft_face) pFT_Done_Face(font->ft_face);
3103 if (font->mapping) unmap_font_file( font->mapping );
3104 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3105 HeapFree(GetProcessHeap(), 0, font->potm);
3106 HeapFree(GetProcessHeap(), 0, font->name);
3107 for (i = 0; i < font->gmsize; i++)
3108 HeapFree(GetProcessHeap(),0,font->gm[i]);
3109 HeapFree(GetProcessHeap(), 0, font->gm);
3110 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3111 HeapFree(GetProcessHeap(), 0, font);
3115 /*************************************************************
3116 * load_VDMX
3118 * load the vdmx entry for the specified height
3121 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3122 ( ( (FT_ULong)_x4 << 24 ) | \
3123 ( (FT_ULong)_x3 << 16 ) | \
3124 ( (FT_ULong)_x2 << 8 ) | \
3125 (FT_ULong)_x1 )
3127 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3129 typedef struct {
3130 BYTE bCharSet;
3131 BYTE xRatio;
3132 BYTE yStartRatio;
3133 BYTE yEndRatio;
3134 } Ratios;
3136 typedef struct {
3137 WORD recs;
3138 BYTE startsz;
3139 BYTE endsz;
3140 } VDMX_group;
3142 static LONG load_VDMX(GdiFont *font, LONG height)
3144 WORD hdr[3], tmp;
3145 VDMX_group group;
3146 BYTE devXRatio, devYRatio;
3147 USHORT numRecs, numRatios;
3148 DWORD result, offset = -1;
3149 LONG ppem = 0;
3150 int i;
3152 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3154 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3155 return ppem;
3157 /* FIXME: need the real device aspect ratio */
3158 devXRatio = 1;
3159 devYRatio = 1;
3161 numRecs = GET_BE_WORD(hdr[1]);
3162 numRatios = GET_BE_WORD(hdr[2]);
3164 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3165 for(i = 0; i < numRatios; i++) {
3166 Ratios ratio;
3168 offset = (3 * 2) + (i * sizeof(Ratios));
3169 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3170 offset = -1;
3172 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3174 if((ratio.xRatio == 0 &&
3175 ratio.yStartRatio == 0 &&
3176 ratio.yEndRatio == 0) ||
3177 (devXRatio == ratio.xRatio &&
3178 devYRatio >= ratio.yStartRatio &&
3179 devYRatio <= ratio.yEndRatio))
3181 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3182 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3183 offset = GET_BE_WORD(tmp);
3184 break;
3188 if(offset == -1) {
3189 FIXME("No suitable ratio found\n");
3190 return ppem;
3193 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3194 USHORT recs;
3195 BYTE startsz, endsz;
3196 WORD *vTable;
3198 recs = GET_BE_WORD(group.recs);
3199 startsz = group.startsz;
3200 endsz = group.endsz;
3202 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3204 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3205 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3206 if(result == GDI_ERROR) {
3207 FIXME("Failed to retrieve vTable\n");
3208 goto end;
3211 if(height > 0) {
3212 for(i = 0; i < recs; i++) {
3213 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3214 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3215 ppem = GET_BE_WORD(vTable[i * 3]);
3217 if(yMax + -yMin == height) {
3218 font->yMax = yMax;
3219 font->yMin = yMin;
3220 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3221 break;
3223 if(yMax + -yMin > height) {
3224 if(--i < 0) {
3225 ppem = 0;
3226 goto end; /* failed */
3228 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3229 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3230 ppem = GET_BE_WORD(vTable[i * 3]);
3231 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3232 break;
3235 if(!font->yMax) {
3236 ppem = 0;
3237 TRACE("ppem not found for height %d\n", height);
3239 } else {
3240 ppem = -height;
3241 if(ppem < startsz || ppem > endsz)
3242 goto end;
3244 for(i = 0; i < recs; i++) {
3245 USHORT yPelHeight;
3246 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3248 if(yPelHeight > ppem)
3249 break; /* failed */
3251 if(yPelHeight == ppem) {
3252 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3253 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3254 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3255 break;
3259 end:
3260 HeapFree(GetProcessHeap(), 0, vTable);
3263 return ppem;
3266 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3268 if(font->font_desc.hash != fd->hash) return TRUE;
3269 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3270 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3271 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3272 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3275 static void calc_hash(FONT_DESC *pfd)
3277 DWORD hash = 0, *ptr, two_chars;
3278 WORD *pwc;
3279 unsigned int i;
3281 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3282 hash ^= *ptr;
3283 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3284 hash ^= *ptr;
3285 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3286 two_chars = *ptr;
3287 pwc = (WCHAR *)&two_chars;
3288 if(!*pwc) break;
3289 *pwc = toupperW(*pwc);
3290 pwc++;
3291 *pwc = toupperW(*pwc);
3292 hash ^= two_chars;
3293 if(!*pwc) break;
3295 hash ^= !pfd->can_use_bitmap;
3296 pfd->hash = hash;
3297 return;
3300 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3302 GdiFont *ret;
3303 FONT_DESC fd;
3304 HFONTLIST *hflist;
3305 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3307 fd.lf = *plf;
3308 fd.matrix = *pmat;
3309 fd.can_use_bitmap = can_use_bitmap;
3310 calc_hash(&fd);
3312 /* try the child list */
3313 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3314 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3315 if(!fontcmp(ret, &fd)) {
3316 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3317 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3318 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3319 if(hflist->hfont == hfont)
3320 return ret;
3325 /* try the in-use list */
3326 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3327 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3328 if(!fontcmp(ret, &fd)) {
3329 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3330 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3331 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3332 if(hflist->hfont == hfont)
3333 return ret;
3335 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3336 hflist->hfont = hfont;
3337 list_add_head(&ret->hfontlist, &hflist->entry);
3338 return ret;
3342 /* then the unused list */
3343 font_elem_ptr = list_head(&unused_gdi_font_list);
3344 while(font_elem_ptr) {
3345 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3346 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3347 if(!fontcmp(ret, &fd)) {
3348 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3349 assert(list_empty(&ret->hfontlist));
3350 TRACE("Found %p in unused list\n", ret);
3351 list_remove(&ret->entry);
3352 list_add_head(&gdi_font_list, &ret->entry);
3353 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3354 hflist->hfont = hfont;
3355 list_add_head(&ret->hfontlist, &hflist->entry);
3356 return ret;
3359 return NULL;
3362 static void add_to_cache(GdiFont *font)
3364 static DWORD cache_num = 1;
3366 font->cache_num = cache_num++;
3367 list_add_head(&gdi_font_list, &font->entry);
3370 /*************************************************************
3371 * create_child_font_list
3373 static BOOL create_child_font_list(GdiFont *font)
3375 BOOL ret = FALSE;
3376 SYSTEM_LINKS *font_link;
3377 CHILD_FONT *font_link_entry, *new_child;
3378 FontSubst *psub;
3379 WCHAR* font_name;
3381 psub = get_font_subst(&font_subst_list, font->name, -1);
3382 font_name = psub ? psub->to.name : font->name;
3383 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3385 if(!strcmpiW(font_link->font_name, font_name))
3387 TRACE("found entry in system list\n");
3388 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3390 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3391 new_child->face = font_link_entry->face;
3392 new_child->font = NULL;
3393 list_add_tail(&font->child_fonts, &new_child->entry);
3394 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3396 ret = TRUE;
3397 break;
3401 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3402 * Sans Serif. This is how asian windows get default fallbacks for fonts
3404 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3405 font->charset != OEM_CHARSET &&
3406 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3407 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3409 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3411 TRACE("found entry in default fallback list\n");
3412 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3414 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3415 new_child->face = font_link_entry->face;
3416 new_child->font = NULL;
3417 list_add_tail(&font->child_fonts, &new_child->entry);
3418 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3420 ret = TRUE;
3421 break;
3425 return ret;
3428 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3430 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3432 if (pFT_Set_Charmap)
3434 FT_Int i;
3435 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3437 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3439 for (i = 0; i < ft_face->num_charmaps; i++)
3441 if (ft_face->charmaps[i]->encoding == encoding)
3443 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3444 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3446 switch (ft_face->charmaps[i]->platform_id)
3448 default:
3449 cmap_def = ft_face->charmaps[i];
3450 break;
3451 case 0: /* Apple Unicode */
3452 cmap0 = ft_face->charmaps[i];
3453 break;
3454 case 1: /* Macintosh */
3455 cmap1 = ft_face->charmaps[i];
3456 break;
3457 case 2: /* ISO */
3458 cmap2 = ft_face->charmaps[i];
3459 break;
3460 case 3: /* Microsoft */
3461 cmap3 = ft_face->charmaps[i];
3462 break;
3466 if (cmap3) /* prefer Microsoft cmap table */
3467 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3468 else if (cmap1)
3469 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3470 else if (cmap2)
3471 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3472 else if (cmap0)
3473 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3474 else if (cmap_def)
3475 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3477 return ft_err == FT_Err_Ok;
3480 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3483 /*************************************************************
3484 * WineEngCreateFontInstance
3487 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3489 GdiFont *ret;
3490 Face *face, *best, *best_bitmap;
3491 Family *family, *last_resort_family;
3492 struct list *family_elem_ptr, *face_elem_ptr;
3493 INT height, width = 0;
3494 unsigned int score = 0, new_score;
3495 signed int diff = 0, newdiff;
3496 BOOL bd, it, can_use_bitmap;
3497 LOGFONTW lf;
3498 CHARSETINFO csi;
3499 HFONTLIST *hflist;
3500 FMAT2 dcmat;
3501 FontSubst *psub = NULL;
3503 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3504 lf.lfWidth = abs(lf.lfWidth);
3506 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3508 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3509 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3510 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3511 lf.lfEscapement);
3513 if(dc->GraphicsMode == GM_ADVANCED)
3514 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3515 else
3517 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3518 font scaling abilities. */
3519 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3520 dcmat.eM21 = dcmat.eM12 = 0;
3523 /* Try to avoid not necessary glyph transformations */
3524 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3526 lf.lfHeight *= fabs(dcmat.eM11);
3527 lf.lfWidth *= fabs(dcmat.eM11);
3528 dcmat.eM11 = dcmat.eM22 = 1.0;
3531 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3532 dcmat.eM21, dcmat.eM22);
3534 GDI_CheckNotLock();
3535 EnterCriticalSection( &freetype_cs );
3537 /* check the cache first */
3538 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3539 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3540 LeaveCriticalSection( &freetype_cs );
3541 return ret;
3544 TRACE("not in cache\n");
3545 if(list_empty(&font_list)) /* No fonts installed */
3547 TRACE("No fonts installed\n");
3548 LeaveCriticalSection( &freetype_cs );
3549 return NULL;
3551 if(!have_installed_roman_font)
3553 TRACE("No roman font installed\n");
3554 LeaveCriticalSection( &freetype_cs );
3555 return NULL;
3558 ret = alloc_font();
3560 ret->font_desc.matrix = dcmat;
3561 ret->font_desc.lf = lf;
3562 ret->font_desc.can_use_bitmap = can_use_bitmap;
3563 calc_hash(&ret->font_desc);
3564 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3565 hflist->hfont = hfont;
3566 list_add_head(&ret->hfontlist, &hflist->entry);
3568 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3569 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3570 original value lfCharSet. Note this is a special case for
3571 Symbol and doesn't happen at least for "Wingdings*" */
3573 if(!strcmpiW(lf.lfFaceName, SymbolW))
3574 lf.lfCharSet = SYMBOL_CHARSET;
3576 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3577 switch(lf.lfCharSet) {
3578 case DEFAULT_CHARSET:
3579 csi.fs.fsCsb[0] = 0;
3580 break;
3581 default:
3582 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3583 csi.fs.fsCsb[0] = 0;
3584 break;
3588 family = NULL;
3589 if(lf.lfFaceName[0] != '\0') {
3590 SYSTEM_LINKS *font_link;
3591 CHILD_FONT *font_link_entry;
3592 LPWSTR FaceName = lf.lfFaceName;
3595 * Check for a leading '@' this signals that the font is being
3596 * requested in tategaki mode (vertical writing substitution) but
3597 * does not affect the fontface that is to be selected.
3599 if (lf.lfFaceName[0]=='@')
3600 FaceName = &lf.lfFaceName[1];
3602 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3604 if(psub) {
3605 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3606 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3607 if (psub->to.charset != -1)
3608 lf.lfCharSet = psub->to.charset;
3611 /* We want a match on name and charset or just name if
3612 charset was DEFAULT_CHARSET. If the latter then
3613 we fixup the returned charset later in get_nearest_charset
3614 where we'll either use the charset of the current ansi codepage
3615 or if that's unavailable the first charset that the font supports.
3617 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3618 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3619 if (!strcmpiW(family->FamilyName, FaceName) ||
3620 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3622 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3623 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3624 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3625 if(face->scalable || can_use_bitmap)
3626 goto found;
3632 * Try check the SystemLink list first for a replacement font.
3633 * We may find good replacements there.
3635 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3637 if(!strcmpiW(font_link->font_name, FaceName) ||
3638 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3640 TRACE("found entry in system list\n");
3641 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3643 face = font_link_entry->face;
3644 family = face->family;
3645 if(csi.fs.fsCsb[0] &
3646 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3648 if(face->scalable || can_use_bitmap)
3649 goto found;
3656 psub = NULL; /* substitution is no more relevant */
3658 /* If requested charset was DEFAULT_CHARSET then try using charset
3659 corresponding to the current ansi codepage */
3660 if (!csi.fs.fsCsb[0])
3662 INT acp = GetACP();
3663 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3664 FIXME("TCI failed on codepage %d\n", acp);
3665 csi.fs.fsCsb[0] = 0;
3666 } else
3667 lf.lfCharSet = csi.ciCharset;
3670 /* Face families are in the top 4 bits of lfPitchAndFamily,
3671 so mask with 0xF0 before testing */
3673 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3674 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3675 strcpyW(lf.lfFaceName, defFixed);
3676 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3677 strcpyW(lf.lfFaceName, defSerif);
3678 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3679 strcpyW(lf.lfFaceName, defSans);
3680 else
3681 strcpyW(lf.lfFaceName, defSans);
3682 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3683 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3684 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3685 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3686 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3687 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3688 if(face->scalable || can_use_bitmap)
3689 goto found;
3694 last_resort_family = NULL;
3695 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3696 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3697 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3698 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3699 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3700 if(face->scalable)
3701 goto found;
3702 if(can_use_bitmap && !last_resort_family)
3703 last_resort_family = family;
3708 if(last_resort_family) {
3709 family = last_resort_family;
3710 csi.fs.fsCsb[0] = 0;
3711 goto found;
3714 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3715 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3716 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3717 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3718 if(face->scalable) {
3719 csi.fs.fsCsb[0] = 0;
3720 WARN("just using first face for now\n");
3721 goto found;
3723 if(can_use_bitmap && !last_resort_family)
3724 last_resort_family = family;
3727 if(!last_resort_family) {
3728 FIXME("can't find a single appropriate font - bailing\n");
3729 free_font(ret);
3730 LeaveCriticalSection( &freetype_cs );
3731 return NULL;
3734 WARN("could only find a bitmap font - this will probably look awful!\n");
3735 family = last_resort_family;
3736 csi.fs.fsCsb[0] = 0;
3738 found:
3739 it = lf.lfItalic ? 1 : 0;
3740 bd = lf.lfWeight > 550 ? 1 : 0;
3742 height = lf.lfHeight;
3744 face = best = best_bitmap = NULL;
3745 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3747 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3749 BOOL italic, bold;
3751 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3752 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3753 new_score = (italic ^ it) + (bold ^ bd);
3754 if(!best || new_score <= score)
3756 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3757 italic, bold, it, bd);
3758 score = new_score;
3759 best = face;
3760 if(best->scalable && score == 0) break;
3761 if(!best->scalable)
3763 if(height > 0)
3764 newdiff = height - (signed int)(best->size.height);
3765 else
3766 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3767 if(!best_bitmap || new_score < score ||
3768 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3770 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3771 diff = newdiff;
3772 best_bitmap = best;
3773 if(score == 0 && diff == 0) break;
3779 if(best)
3780 face = best->scalable ? best : best_bitmap;
3781 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3782 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3784 ret->fs = face->fs;
3786 if(csi.fs.fsCsb[0]) {
3787 ret->charset = lf.lfCharSet;
3788 ret->codepage = csi.ciACP;
3790 else
3791 ret->charset = get_nearest_charset(face, &ret->codepage);
3793 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3794 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3796 ret->aveWidth = height ? lf.lfWidth : 0;
3798 if(!face->scalable) {
3799 /* Windows uses integer scaling factors for bitmap fonts */
3800 INT scale, scaled_height;
3802 /* FIXME: rotation of bitmap fonts is ignored */
3803 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3804 if (ret->aveWidth)
3805 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3806 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3808 if (height != 0) height = diff;
3809 height += face->size.height;
3811 scale = (height + face->size.height - 1) / face->size.height;
3812 scaled_height = scale * face->size.height;
3813 /* Only jump to the next height if the difference <= 25% original height */
3814 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3815 /* The jump between unscaled and doubled is delayed by 1 */
3816 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3817 ret->scale_y = scale;
3819 width = face->size.x_ppem >> 6;
3820 height = face->size.y_ppem >> 6;
3822 else
3823 ret->scale_y = 1.0;
3824 TRACE("font scale y: %f\n", ret->scale_y);
3826 ret->ft_face = OpenFontFace(ret, face, width, height);
3828 if (!ret->ft_face)
3830 free_font( ret );
3831 LeaveCriticalSection( &freetype_cs );
3832 return 0;
3835 ret->ntmFlags = face->ntmFlags;
3837 if (ret->charset == SYMBOL_CHARSET &&
3838 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3839 /* No ops */
3841 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3842 /* No ops */
3844 else {
3845 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3848 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3849 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3850 ret->underline = lf.lfUnderline ? 0xff : 0;
3851 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3852 create_child_font_list(ret);
3854 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3856 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3857 if (length != GDI_ERROR)
3859 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3860 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3861 TRACE("Loaded GSUB table of %i bytes\n",length);
3865 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3867 add_to_cache(ret);
3868 LeaveCriticalSection( &freetype_cs );
3869 return ret;
3872 static void dump_gdi_font_list(void)
3874 GdiFont *gdiFont;
3875 struct list *elem_ptr;
3877 TRACE("---------- gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3879 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3884 TRACE("---------- Unused gdiFont Cache ----------\n");
3885 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3886 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3887 TRACE("gdiFont=%p %s %d\n",
3888 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3892 /*************************************************************
3893 * WineEngDestroyFontInstance
3895 * free the gdiFont associated with this handle
3898 BOOL WineEngDestroyFontInstance(HFONT handle)
3900 GdiFont *gdiFont;
3901 HFONTLIST *hflist;
3902 BOOL ret = FALSE;
3903 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3904 int i = 0;
3906 GDI_CheckNotLock();
3907 EnterCriticalSection( &freetype_cs );
3909 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3911 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3912 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3913 if(hflist->hfont == handle)
3915 TRACE("removing child font %p from child list\n", gdiFont);
3916 list_remove(&gdiFont->entry);
3917 LeaveCriticalSection( &freetype_cs );
3918 return TRUE;
3922 TRACE("destroying hfont=%p\n", handle);
3923 if(TRACE_ON(font))
3924 dump_gdi_font_list();
3926 font_elem_ptr = list_head(&gdi_font_list);
3927 while(font_elem_ptr) {
3928 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3929 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3931 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3932 while(hfontlist_elem_ptr) {
3933 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3934 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3935 if(hflist->hfont == handle) {
3936 list_remove(&hflist->entry);
3937 HeapFree(GetProcessHeap(), 0, hflist);
3938 ret = TRUE;
3941 if(list_empty(&gdiFont->hfontlist)) {
3942 TRACE("Moving to Unused list\n");
3943 list_remove(&gdiFont->entry);
3944 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3949 font_elem_ptr = list_head(&unused_gdi_font_list);
3950 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3951 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3952 while(font_elem_ptr) {
3953 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3954 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3955 TRACE("freeing %p\n", gdiFont);
3956 list_remove(&gdiFont->entry);
3957 free_font(gdiFont);
3959 LeaveCriticalSection( &freetype_cs );
3960 return ret;
3963 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3964 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3966 GdiFont *font;
3967 LONG width, height;
3969 if (face->cached_enum_data)
3971 TRACE("Cached\n");
3972 *pelf = face->cached_enum_data->elf;
3973 *pntm = face->cached_enum_data->ntm;
3974 *ptype = face->cached_enum_data->type;
3975 return;
3978 font = alloc_font();
3980 if(face->scalable) {
3981 height = -2048; /* 2048 is the most common em size */
3982 width = 0;
3983 } else {
3984 height = face->size.y_ppem >> 6;
3985 width = face->size.x_ppem >> 6;
3987 font->scale_y = 1.0;
3989 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3991 free_font(font);
3992 return;
3995 font->name = strdupW(face->family->FamilyName);
3996 font->ntmFlags = face->ntmFlags;
3998 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4000 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4002 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4004 lstrcpynW(pelf->elfLogFont.lfFaceName,
4005 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4006 LF_FACESIZE);
4007 lstrcpynW(pelf->elfFullName,
4008 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4009 LF_FULLFACESIZE);
4010 lstrcpynW(pelf->elfStyle,
4011 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4012 LF_FACESIZE);
4014 else
4016 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4018 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4020 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4021 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4022 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4025 pntm->ntmTm.ntmFlags = face->ntmFlags;
4026 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4027 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4028 pntm->ntmFontSig = face->fs;
4030 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4032 pelf->elfLogFont.lfEscapement = 0;
4033 pelf->elfLogFont.lfOrientation = 0;
4034 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4035 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4036 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4037 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4038 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4039 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4040 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4041 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4042 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4043 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4044 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4046 *ptype = 0;
4047 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4048 *ptype |= TRUETYPE_FONTTYPE;
4049 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4050 *ptype |= DEVICE_FONTTYPE;
4051 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4052 *ptype |= RASTER_FONTTYPE;
4054 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4055 if (face->cached_enum_data)
4057 face->cached_enum_data->elf = *pelf;
4058 face->cached_enum_data->ntm = *pntm;
4059 face->cached_enum_data->type = *ptype;
4062 free_font(font);
4065 /*************************************************************
4066 * WineEngEnumFonts
4069 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4071 Family *family;
4072 Face *face;
4073 struct list *family_elem_ptr, *face_elem_ptr;
4074 ENUMLOGFONTEXW elf;
4075 NEWTEXTMETRICEXW ntm;
4076 DWORD type;
4077 FONTSIGNATURE fs;
4078 CHARSETINFO csi;
4079 LOGFONTW lf;
4080 int i;
4082 if (!plf)
4084 lf.lfCharSet = DEFAULT_CHARSET;
4085 lf.lfPitchAndFamily = 0;
4086 lf.lfFaceName[0] = 0;
4087 plf = &lf;
4090 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4092 GDI_CheckNotLock();
4093 EnterCriticalSection( &freetype_cs );
4094 if(plf->lfFaceName[0]) {
4095 FontSubst *psub;
4096 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4098 if(psub) {
4099 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4100 debugstr_w(psub->to.name));
4101 lf = *plf;
4102 strcpyW(lf.lfFaceName, psub->to.name);
4103 plf = &lf;
4106 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4107 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4108 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
4109 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4110 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4111 GetEnumStructs(face, &elf, &ntm, &type);
4112 for(i = 0; i < 32; i++) {
4113 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4114 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4115 strcpyW(elf.elfScript, OEM_DOSW);
4116 i = 32; /* break out of loop */
4117 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4118 continue;
4119 else {
4120 fs.fsCsb[0] = 1L << i;
4121 fs.fsCsb[1] = 0;
4122 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4123 TCI_SRCFONTSIG))
4124 csi.ciCharset = DEFAULT_CHARSET;
4125 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4126 if(csi.ciCharset != DEFAULT_CHARSET) {
4127 elf.elfLogFont.lfCharSet =
4128 ntm.ntmTm.tmCharSet = csi.ciCharset;
4129 if(ElfScriptsW[i])
4130 strcpyW(elf.elfScript, ElfScriptsW[i]);
4131 else
4132 FIXME("Unknown elfscript for bit %d\n", i);
4135 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4136 debugstr_w(elf.elfLogFont.lfFaceName),
4137 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4138 csi.ciCharset, type, debugstr_w(elf.elfScript),
4139 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4140 ntm.ntmTm.ntmFlags);
4141 /* release section before callback (FIXME) */
4142 LeaveCriticalSection( &freetype_cs );
4143 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4144 EnterCriticalSection( &freetype_cs );
4149 } else {
4150 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4151 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4152 face_elem_ptr = list_head(&family->faces);
4153 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4154 GetEnumStructs(face, &elf, &ntm, &type);
4155 for(i = 0; i < 32; i++) {
4156 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4157 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4158 strcpyW(elf.elfScript, OEM_DOSW);
4159 i = 32; /* break out of loop */
4160 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4161 continue;
4162 else {
4163 fs.fsCsb[0] = 1L << i;
4164 fs.fsCsb[1] = 0;
4165 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4166 TCI_SRCFONTSIG))
4167 csi.ciCharset = DEFAULT_CHARSET;
4168 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4169 if(csi.ciCharset != DEFAULT_CHARSET) {
4170 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4171 csi.ciCharset;
4172 if(ElfScriptsW[i])
4173 strcpyW(elf.elfScript, ElfScriptsW[i]);
4174 else
4175 FIXME("Unknown elfscript for bit %d\n", i);
4178 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4179 debugstr_w(elf.elfLogFont.lfFaceName),
4180 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4181 csi.ciCharset, type, debugstr_w(elf.elfScript),
4182 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4183 ntm.ntmTm.ntmFlags);
4184 /* release section before callback (FIXME) */
4185 LeaveCriticalSection( &freetype_cs );
4186 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4187 EnterCriticalSection( &freetype_cs );
4191 LeaveCriticalSection( &freetype_cs );
4192 return 1;
4195 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4197 pt->x.value = vec->x >> 6;
4198 pt->x.fract = (vec->x & 0x3f) << 10;
4199 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4200 pt->y.value = vec->y >> 6;
4201 pt->y.fract = (vec->y & 0x3f) << 10;
4202 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4203 return;
4206 /***************************************************
4207 * According to the MSDN documentation on WideCharToMultiByte,
4208 * certain codepages cannot set the default_used parameter.
4209 * This returns TRUE if the codepage can set that parameter, false else
4210 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4212 static BOOL codepage_sets_default_used(UINT codepage)
4214 switch (codepage)
4216 case CP_UTF7:
4217 case CP_UTF8:
4218 case CP_SYMBOL:
4219 return FALSE;
4220 default:
4221 return TRUE;
4226 * GSUB Table handling functions
4229 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4231 const GSUB_CoverageFormat1* cf1;
4233 cf1 = table;
4235 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4237 int count = GET_BE_WORD(cf1->GlyphCount);
4238 int i;
4239 TRACE("Coverage Format 1, %i glyphs\n",count);
4240 for (i = 0; i < count; i++)
4241 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4242 return i;
4243 return -1;
4245 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4247 const GSUB_CoverageFormat2* cf2;
4248 int i;
4249 int count;
4250 cf2 = (GSUB_CoverageFormat2*)cf1;
4252 count = GET_BE_WORD(cf2->RangeCount);
4253 TRACE("Coverage Format 2, %i ranges\n",count);
4254 for (i = 0; i < count; i++)
4256 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4257 return -1;
4258 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4259 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4261 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4262 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4265 return -1;
4267 else
4268 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4270 return -1;
4273 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4275 const GSUB_ScriptList *script;
4276 const GSUB_Script *deflt = NULL;
4277 int i;
4278 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4280 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4281 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4283 const GSUB_Script *scr;
4284 int offset;
4286 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4287 scr = (GSUB_Script*)((LPBYTE)script + offset);
4289 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4290 return scr;
4291 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4292 deflt = scr;
4294 return deflt;
4297 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4299 int i;
4300 int offset;
4301 const GSUB_LangSys *Lang;
4303 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4305 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4307 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4308 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4310 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4311 return Lang;
4313 offset = GET_BE_WORD(script->DefaultLangSys);
4314 if (offset)
4316 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4317 return Lang;
4319 return NULL;
4322 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4324 int i;
4325 const GSUB_FeatureList *feature;
4326 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4328 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4329 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4331 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4332 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4334 const GSUB_Feature *feat;
4335 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4336 return feat;
4339 return NULL;
4342 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4344 int i;
4345 int offset;
4346 const GSUB_LookupList *lookup;
4347 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4349 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4350 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4352 const GSUB_LookupTable *look;
4353 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4354 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4355 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4356 if (GET_BE_WORD(look->LookupType) != 1)
4357 FIXME("We only handle SubType 1\n");
4358 else
4360 int j;
4362 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4364 const GSUB_SingleSubstFormat1 *ssf1;
4365 offset = GET_BE_WORD(look->SubTable[j]);
4366 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4367 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4369 int offset = GET_BE_WORD(ssf1->Coverage);
4370 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4371 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4373 TRACE(" Glyph 0x%x ->",glyph);
4374 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4375 TRACE(" 0x%x\n",glyph);
4378 else
4380 const GSUB_SingleSubstFormat2 *ssf2;
4381 INT index;
4382 INT offset;
4384 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4385 offset = GET_BE_WORD(ssf1->Coverage);
4386 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4387 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4388 TRACE(" Coverage index %i\n",index);
4389 if (index != -1)
4391 TRACE(" Glyph is 0x%x ->",glyph);
4392 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4393 TRACE("0x%x\n",glyph);
4399 return glyph;
4402 static const char* get_opentype_script(const GdiFont *font)
4405 * I am not sure if this is the correct way to generate our script tag
4408 switch (font->charset)
4410 case ANSI_CHARSET: return "latn";
4411 case BALTIC_CHARSET: return "latn"; /* ?? */
4412 case CHINESEBIG5_CHARSET: return "hani";
4413 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4414 case GB2312_CHARSET: return "hani";
4415 case GREEK_CHARSET: return "grek";
4416 case HANGUL_CHARSET: return "hang";
4417 case RUSSIAN_CHARSET: return "cyrl";
4418 case SHIFTJIS_CHARSET: return "kana";
4419 case TURKISH_CHARSET: return "latn"; /* ?? */
4420 case VIETNAMESE_CHARSET: return "latn";
4421 case JOHAB_CHARSET: return "latn"; /* ?? */
4422 case ARABIC_CHARSET: return "arab";
4423 case HEBREW_CHARSET: return "hebr";
4424 case THAI_CHARSET: return "thai";
4425 default: return "latn";
4429 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4431 const GSUB_Header *header;
4432 const GSUB_Script *script;
4433 const GSUB_LangSys *language;
4434 const GSUB_Feature *feature;
4436 if (!font->GSUB_Table)
4437 return glyph;
4439 header = font->GSUB_Table;
4441 script = GSUB_get_script_table(header, get_opentype_script(font));
4442 if (!script)
4444 TRACE("Script not found\n");
4445 return glyph;
4447 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4448 if (!language)
4450 TRACE("Language not found\n");
4451 return glyph;
4453 feature = GSUB_get_feature(header, language, "vrt2");
4454 if (!feature)
4455 feature = GSUB_get_feature(header, language, "vert");
4456 if (!feature)
4458 TRACE("vrt2/vert feature not found\n");
4459 return glyph;
4461 return GSUB_apply_feature(header, feature, glyph);
4464 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4466 FT_UInt glyphId;
4468 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4469 WCHAR wc = (WCHAR)glyph;
4470 BOOL default_used;
4471 BOOL *default_used_pointer;
4472 FT_UInt ret;
4473 char buf;
4474 default_used_pointer = NULL;
4475 default_used = FALSE;
4476 if (codepage_sets_default_used(font->codepage))
4477 default_used_pointer = &default_used;
4478 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4479 ret = 0;
4480 else
4481 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4482 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4483 return get_GSUB_vert_glyph(font,ret);
4486 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4487 glyph = glyph + 0xf000;
4488 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4489 return get_GSUB_vert_glyph(font,glyphId);
4492 /*************************************************************
4493 * WineEngGetGlyphIndices
4496 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4497 LPWORD pgi, DWORD flags)
4499 int i;
4500 int default_char = -1;
4502 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4504 for(i = 0; i < count; i++)
4506 pgi[i] = get_glyph_index(font, lpstr[i]);
4507 if (pgi[i] == 0)
4509 if (default_char == -1)
4511 if (FT_IS_SFNT(font->ft_face))
4513 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4514 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4516 else
4518 TEXTMETRICW textm;
4519 WineEngGetTextMetrics(font, &textm);
4520 default_char = textm.tmDefaultChar;
4523 pgi[i] = default_char;
4526 return count;
4529 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4531 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4532 return !memcmp(matrix, &identity, sizeof(FMAT2));
4535 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4537 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4538 return !memcmp(matrix, &identity, sizeof(MAT2));
4541 /*************************************************************
4542 * WineEngGetGlyphOutline
4544 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4545 * except that the first parameter is the HWINEENGFONT of the font in
4546 * question rather than an HDC.
4549 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4550 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4551 const MAT2* lpmat)
4553 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4554 FT_Face ft_face = incoming_font->ft_face;
4555 GdiFont *font = incoming_font;
4556 FT_UInt glyph_index;
4557 DWORD width, height, pitch, needed = 0;
4558 FT_Bitmap ft_bitmap;
4559 FT_Error err;
4560 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4561 FT_Angle angle = 0;
4562 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4563 double widthRatio = 1.0;
4564 FT_Matrix transMat = identityMat;
4565 FT_Matrix transMatUnrotated;
4566 BOOL needsTransform = FALSE;
4567 BOOL tategaki = (font->GSUB_Table != NULL);
4568 UINT original_index;
4570 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4571 buflen, buf, lpmat);
4573 TRACE("font transform %f %f %f %f\n",
4574 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4575 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4577 GDI_CheckNotLock();
4578 EnterCriticalSection( &freetype_cs );
4580 if(format & GGO_GLYPH_INDEX) {
4581 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4582 original_index = glyph;
4583 format &= ~GGO_GLYPH_INDEX;
4584 } else {
4585 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4586 ft_face = font->ft_face;
4587 original_index = glyph_index;
4590 if(format & GGO_UNHINTED) {
4591 load_flags |= FT_LOAD_NO_HINTING;
4592 format &= ~GGO_UNHINTED;
4595 /* tategaki never appears to happen to lower glyph index */
4596 if (glyph_index < TATEGAKI_LOWER_BOUND )
4597 tategaki = FALSE;
4599 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4600 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4601 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4602 font->gmsize * sizeof(GM*));
4603 } else {
4604 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4605 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4607 *lpgm = FONT_GM(font,original_index)->gm;
4608 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4609 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4610 lpgm->gmCellIncX, lpgm->gmCellIncY);
4611 LeaveCriticalSection( &freetype_cs );
4612 return 1; /* FIXME */
4616 if (!font->gm[original_index / GM_BLOCK_SIZE])
4617 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4619 /* Scaling factor */
4620 if (font->aveWidth)
4622 TEXTMETRICW tm;
4624 WineEngGetTextMetrics(font, &tm);
4626 widthRatio = (double)font->aveWidth;
4627 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4629 else
4630 widthRatio = font->scale_y;
4632 /* Scaling transform */
4633 if (widthRatio != 1.0 || font->scale_y != 1.0)
4635 FT_Matrix scaleMat;
4636 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4637 scaleMat.xy = 0;
4638 scaleMat.yx = 0;
4639 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4641 pFT_Matrix_Multiply(&scaleMat, &transMat);
4642 needsTransform = TRUE;
4645 /* Slant transform */
4646 if (font->fake_italic) {
4647 FT_Matrix slantMat;
4649 slantMat.xx = (1 << 16);
4650 slantMat.xy = ((1 << 16) >> 2);
4651 slantMat.yx = 0;
4652 slantMat.yy = (1 << 16);
4653 pFT_Matrix_Multiply(&slantMat, &transMat);
4654 needsTransform = TRUE;
4657 /* Rotation transform */
4658 transMatUnrotated = transMat;
4659 if(font->orientation && !tategaki) {
4660 FT_Matrix rotationMat;
4661 FT_Vector vecAngle;
4662 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4663 pFT_Vector_Unit(&vecAngle, angle);
4664 rotationMat.xx = vecAngle.x;
4665 rotationMat.xy = -vecAngle.y;
4666 rotationMat.yx = -rotationMat.xy;
4667 rotationMat.yy = rotationMat.xx;
4669 pFT_Matrix_Multiply(&rotationMat, &transMat);
4670 needsTransform = TRUE;
4673 /* World transform */
4674 if (!is_identity_FMAT2(&font->font_desc.matrix))
4676 FT_Matrix worldMat;
4677 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4678 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4679 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4680 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4681 pFT_Matrix_Multiply(&worldMat, &transMat);
4682 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4683 needsTransform = TRUE;
4686 /* Extra transformation specified by caller */
4687 if (!is_identity_MAT2(lpmat))
4689 FT_Matrix extraMat;
4690 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4691 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4692 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4693 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4694 pFT_Matrix_Multiply(&extraMat, &transMat);
4695 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4696 needsTransform = TRUE;
4699 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4700 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4701 format == GGO_GRAY8_BITMAP))
4703 load_flags |= FT_LOAD_NO_BITMAP;
4706 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4708 if(err) {
4709 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4710 LeaveCriticalSection( &freetype_cs );
4711 return GDI_ERROR;
4714 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4715 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4717 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4718 lsb = left >> 6;
4719 bbx = (right - left) >> 6;
4721 if(!needsTransform) {
4722 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4723 bottom = (ft_face->glyph->metrics.horiBearingY -
4724 ft_face->glyph->metrics.height) & -64;
4725 lpgm->gmCellIncX = adv;
4726 lpgm->gmCellIncY = 0;
4727 } else {
4728 INT xc, yc;
4729 FT_Vector vec;
4730 for(xc = 0; xc < 2; xc++) {
4731 for(yc = 0; yc < 2; yc++) {
4732 vec.x = (ft_face->glyph->metrics.horiBearingX +
4733 xc * ft_face->glyph->metrics.width);
4734 vec.y = ft_face->glyph->metrics.horiBearingY -
4735 yc * ft_face->glyph->metrics.height;
4736 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4737 pFT_Vector_Transform(&vec, &transMat);
4738 if(xc == 0 && yc == 0) {
4739 left = right = vec.x;
4740 top = bottom = vec.y;
4741 } else {
4742 if(vec.x < left) left = vec.x;
4743 else if(vec.x > right) right = vec.x;
4744 if(vec.y < bottom) bottom = vec.y;
4745 else if(vec.y > top) top = vec.y;
4749 left = left & -64;
4750 right = (right + 63) & -64;
4751 bottom = bottom & -64;
4752 top = (top + 63) & -64;
4754 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4755 vec.x = ft_face->glyph->metrics.horiAdvance;
4756 vec.y = 0;
4757 pFT_Vector_Transform(&vec, &transMat);
4758 lpgm->gmCellIncX = (vec.x+63) >> 6;
4759 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4761 vec.x = ft_face->glyph->metrics.horiAdvance;
4762 vec.y = 0;
4763 pFT_Vector_Transform(&vec, &transMatUnrotated);
4764 adv = (vec.x+63) >> 6;
4766 lpgm->gmBlackBoxX = (right - left) >> 6;
4767 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4768 lpgm->gmptGlyphOrigin.x = left >> 6;
4769 lpgm->gmptGlyphOrigin.y = top >> 6;
4771 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4772 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4773 lpgm->gmCellIncX, lpgm->gmCellIncY);
4775 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4776 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4778 FONT_GM(font,original_index)->gm = *lpgm;
4779 FONT_GM(font,original_index)->adv = adv;
4780 FONT_GM(font,original_index)->lsb = lsb;
4781 FONT_GM(font,original_index)->bbx = bbx;
4782 FONT_GM(font,original_index)->init = TRUE;
4785 if(format == GGO_METRICS)
4787 LeaveCriticalSection( &freetype_cs );
4788 return 1; /* FIXME */
4791 if(ft_face->glyph->format != ft_glyph_format_outline &&
4792 (format == GGO_NATIVE || format == GGO_BEZIER ||
4793 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4794 format == GGO_GRAY8_BITMAP))
4796 TRACE("loaded a bitmap\n");
4797 LeaveCriticalSection( &freetype_cs );
4798 return GDI_ERROR;
4801 switch(format) {
4802 case GGO_BITMAP:
4803 width = lpgm->gmBlackBoxX;
4804 height = lpgm->gmBlackBoxY;
4805 pitch = ((width + 31) >> 5) << 2;
4806 needed = pitch * height;
4808 if(!buf || !buflen) break;
4810 switch(ft_face->glyph->format) {
4811 case ft_glyph_format_bitmap:
4813 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4814 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4815 INT h = ft_face->glyph->bitmap.rows;
4816 while(h--) {
4817 memcpy(dst, src, w);
4818 src += ft_face->glyph->bitmap.pitch;
4819 dst += pitch;
4821 break;
4824 case ft_glyph_format_outline:
4825 ft_bitmap.width = width;
4826 ft_bitmap.rows = height;
4827 ft_bitmap.pitch = pitch;
4828 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4829 ft_bitmap.buffer = buf;
4831 if(needsTransform)
4832 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4834 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4836 /* Note: FreeType will only set 'black' bits for us. */
4837 memset(buf, 0, needed);
4838 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4839 break;
4841 default:
4842 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4843 LeaveCriticalSection( &freetype_cs );
4844 return GDI_ERROR;
4846 break;
4848 case GGO_GRAY2_BITMAP:
4849 case GGO_GRAY4_BITMAP:
4850 case GGO_GRAY8_BITMAP:
4851 case WINE_GGO_GRAY16_BITMAP:
4853 unsigned int mult, row, col;
4854 BYTE *start, *ptr;
4856 width = lpgm->gmBlackBoxX;
4857 height = lpgm->gmBlackBoxY;
4858 pitch = (width + 3) / 4 * 4;
4859 needed = pitch * height;
4861 if(!buf || !buflen) break;
4863 switch(ft_face->glyph->format) {
4864 case ft_glyph_format_bitmap:
4866 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4867 INT h = ft_face->glyph->bitmap.rows;
4868 INT x;
4869 while(h--) {
4870 for(x = 0; x < pitch; x++)
4872 if(x < ft_face->glyph->bitmap.width)
4873 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4874 else
4875 dst[x] = 0;
4877 src += ft_face->glyph->bitmap.pitch;
4878 dst += pitch;
4880 LeaveCriticalSection( &freetype_cs );
4881 return needed;
4883 case ft_glyph_format_outline:
4885 ft_bitmap.width = width;
4886 ft_bitmap.rows = height;
4887 ft_bitmap.pitch = pitch;
4888 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4889 ft_bitmap.buffer = buf;
4891 if(needsTransform)
4892 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4894 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4896 memset(ft_bitmap.buffer, 0, buflen);
4898 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4900 if(format == GGO_GRAY2_BITMAP)
4901 mult = 4;
4902 else if(format == GGO_GRAY4_BITMAP)
4903 mult = 16;
4904 else if(format == GGO_GRAY8_BITMAP)
4905 mult = 64;
4906 else /* format == WINE_GGO_GRAY16_BITMAP */
4908 LeaveCriticalSection( &freetype_cs );
4909 return needed;
4911 break;
4913 default:
4914 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4915 LeaveCriticalSection( &freetype_cs );
4916 return GDI_ERROR;
4919 start = buf;
4920 for(row = 0; row < height; row++) {
4921 ptr = start;
4922 for(col = 0; col < width; col++, ptr++) {
4923 *ptr = (((int)*ptr) * mult + 128) / 256;
4925 start += pitch;
4927 break;
4930 case WINE_GGO_HRGB_BITMAP:
4931 case WINE_GGO_HBGR_BITMAP:
4932 case WINE_GGO_VRGB_BITMAP:
4933 case WINE_GGO_VBGR_BITMAP:
4934 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4936 switch (ft_face->glyph->format)
4938 case FT_GLYPH_FORMAT_BITMAP:
4940 BYTE *src, *dst;
4941 INT src_pitch, x;
4943 width = lpgm->gmBlackBoxX;
4944 height = lpgm->gmBlackBoxY;
4945 pitch = width * 4;
4946 needed = pitch * height;
4948 if (!buf || !buflen) break;
4950 memset(buf, 0, buflen);
4951 dst = buf;
4952 src = ft_face->glyph->bitmap.buffer;
4953 src_pitch = ft_face->glyph->bitmap.pitch;
4955 while ( height-- )
4957 for (x = 0; x < width; x++)
4959 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4960 ((unsigned int *)dst)[x] = ~0u;
4962 src += src_pitch;
4963 dst += pitch;
4966 break;
4969 case FT_GLYPH_FORMAT_OUTLINE:
4971 unsigned int *dst;
4972 BYTE *src;
4973 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4974 INT x_shift, y_shift;
4975 BOOL rgb;
4976 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4977 FT_Render_Mode render_mode =
4978 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4979 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4981 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4983 if ( render_mode == FT_RENDER_MODE_LCD)
4985 lpgm->gmBlackBoxX += 2;
4986 lpgm->gmptGlyphOrigin.x -= 1;
4988 else
4990 lpgm->gmBlackBoxY += 2;
4991 lpgm->gmptGlyphOrigin.y += 1;
4995 width = lpgm->gmBlackBoxX;
4996 height = lpgm->gmBlackBoxY;
4997 pitch = width * 4;
4998 needed = pitch * height;
5000 if (!buf || !buflen) break;
5002 memset(buf, 0, buflen);
5003 dst = buf;
5004 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5006 if ( needsTransform )
5007 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5009 if ( pFT_Library_SetLcdFilter )
5010 pFT_Library_SetLcdFilter( library, lcdfilter );
5011 pFT_Render_Glyph (ft_face->glyph, render_mode);
5013 src = ft_face->glyph->bitmap.buffer;
5014 src_pitch = ft_face->glyph->bitmap.pitch;
5015 src_width = ft_face->glyph->bitmap.width;
5016 src_height = ft_face->glyph->bitmap.rows;
5018 if ( render_mode == FT_RENDER_MODE_LCD)
5020 rgb_interval = 1;
5021 hmul = 3;
5022 vmul = 1;
5024 else
5026 rgb_interval = src_pitch;
5027 hmul = 1;
5028 vmul = 3;
5031 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5032 if ( x_shift < 0 ) x_shift = 0;
5033 if ( x_shift + (src_width / hmul) > width )
5034 x_shift = width - (src_width / hmul);
5036 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5037 if ( y_shift < 0 ) y_shift = 0;
5038 if ( y_shift + (src_height / vmul) > height )
5039 y_shift = height - (src_height / vmul);
5041 dst += x_shift + y_shift * ( pitch / 4 );
5042 while ( src_height )
5044 for ( x = 0; x < src_width / hmul; x++ )
5046 if ( rgb )
5048 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5049 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5050 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5051 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5053 else
5055 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5056 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5057 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5058 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5061 src += src_pitch * vmul;
5062 dst += pitch / 4;
5063 src_height -= vmul;
5066 break;
5069 default:
5070 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5071 LeaveCriticalSection ( &freetype_cs );
5072 return GDI_ERROR;
5075 break;
5077 #else
5078 LeaveCriticalSection( &freetype_cs );
5079 return GDI_ERROR;
5080 #endif
5082 case GGO_NATIVE:
5084 int contour, point = 0, first_pt;
5085 FT_Outline *outline = &ft_face->glyph->outline;
5086 TTPOLYGONHEADER *pph;
5087 TTPOLYCURVE *ppc;
5088 DWORD pph_start, cpfx, type;
5090 if(buflen == 0) buf = NULL;
5092 if (needsTransform && buf) {
5093 pFT_Outline_Transform(outline, &transMat);
5096 for(contour = 0; contour < outline->n_contours; contour++) {
5097 pph_start = needed;
5098 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5099 first_pt = point;
5100 if(buf) {
5101 pph->dwType = TT_POLYGON_TYPE;
5102 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5104 needed += sizeof(*pph);
5105 point++;
5106 while(point <= outline->contours[contour]) {
5107 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5108 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5109 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5110 cpfx = 0;
5111 do {
5112 if(buf)
5113 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5114 cpfx++;
5115 point++;
5116 } while(point <= outline->contours[contour] &&
5117 (outline->tags[point] & FT_Curve_Tag_On) ==
5118 (outline->tags[point-1] & FT_Curve_Tag_On));
5119 /* At the end of a contour Windows adds the start point, but
5120 only for Beziers */
5121 if(point > outline->contours[contour] &&
5122 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5123 if(buf)
5124 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5125 cpfx++;
5126 } else if(point <= outline->contours[contour] &&
5127 outline->tags[point] & FT_Curve_Tag_On) {
5128 /* add closing pt for bezier */
5129 if(buf)
5130 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5131 cpfx++;
5132 point++;
5134 if(buf) {
5135 ppc->wType = type;
5136 ppc->cpfx = cpfx;
5138 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5140 if(buf)
5141 pph->cb = needed - pph_start;
5143 break;
5145 case GGO_BEZIER:
5147 /* Convert the quadratic Beziers to cubic Beziers.
5148 The parametric eqn for a cubic Bezier is, from PLRM:
5149 r(t) = at^3 + bt^2 + ct + r0
5150 with the control points:
5151 r1 = r0 + c/3
5152 r2 = r1 + (c + b)/3
5153 r3 = r0 + c + b + a
5155 A quadratic Beizer has the form:
5156 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5158 So equating powers of t leads to:
5159 r1 = 2/3 p1 + 1/3 p0
5160 r2 = 2/3 p1 + 1/3 p2
5161 and of course r0 = p0, r3 = p2
5164 int contour, point = 0, first_pt;
5165 FT_Outline *outline = &ft_face->glyph->outline;
5166 TTPOLYGONHEADER *pph;
5167 TTPOLYCURVE *ppc;
5168 DWORD pph_start, cpfx, type;
5169 FT_Vector cubic_control[4];
5170 if(buflen == 0) buf = NULL;
5172 if (needsTransform && buf) {
5173 pFT_Outline_Transform(outline, &transMat);
5176 for(contour = 0; contour < outline->n_contours; contour++) {
5177 pph_start = needed;
5178 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5179 first_pt = point;
5180 if(buf) {
5181 pph->dwType = TT_POLYGON_TYPE;
5182 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5184 needed += sizeof(*pph);
5185 point++;
5186 while(point <= outline->contours[contour]) {
5187 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5188 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5189 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5190 cpfx = 0;
5191 do {
5192 if(type == TT_PRIM_LINE) {
5193 if(buf)
5194 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5195 cpfx++;
5196 point++;
5197 } else {
5198 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5199 so cpfx = 3n */
5201 /* FIXME: Possible optimization in endpoint calculation
5202 if there are two consecutive curves */
5203 cubic_control[0] = outline->points[point-1];
5204 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5205 cubic_control[0].x += outline->points[point].x + 1;
5206 cubic_control[0].y += outline->points[point].y + 1;
5207 cubic_control[0].x >>= 1;
5208 cubic_control[0].y >>= 1;
5210 if(point+1 > outline->contours[contour])
5211 cubic_control[3] = outline->points[first_pt];
5212 else {
5213 cubic_control[3] = outline->points[point+1];
5214 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5215 cubic_control[3].x += outline->points[point].x + 1;
5216 cubic_control[3].y += outline->points[point].y + 1;
5217 cubic_control[3].x >>= 1;
5218 cubic_control[3].y >>= 1;
5221 /* r1 = 1/3 p0 + 2/3 p1
5222 r2 = 1/3 p2 + 2/3 p1 */
5223 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5224 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5225 cubic_control[2] = cubic_control[1];
5226 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5227 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5228 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5229 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5230 if(buf) {
5231 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5232 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5233 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5235 cpfx += 3;
5236 point++;
5238 } while(point <= outline->contours[contour] &&
5239 (outline->tags[point] & FT_Curve_Tag_On) ==
5240 (outline->tags[point-1] & FT_Curve_Tag_On));
5241 /* At the end of a contour Windows adds the start point,
5242 but only for Beziers and we've already done that.
5244 if(point <= outline->contours[contour] &&
5245 outline->tags[point] & FT_Curve_Tag_On) {
5246 /* This is the closing pt of a bezier, but we've already
5247 added it, so just inc point and carry on */
5248 point++;
5250 if(buf) {
5251 ppc->wType = type;
5252 ppc->cpfx = cpfx;
5254 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5256 if(buf)
5257 pph->cb = needed - pph_start;
5259 break;
5262 default:
5263 FIXME("Unsupported format %d\n", format);
5264 LeaveCriticalSection( &freetype_cs );
5265 return GDI_ERROR;
5267 LeaveCriticalSection( &freetype_cs );
5268 return needed;
5271 static BOOL get_bitmap_text_metrics(GdiFont *font)
5273 FT_Face ft_face = font->ft_face;
5274 #ifdef HAVE_FREETYPE_FTWINFNT_H
5275 FT_WinFNT_HeaderRec winfnt_header;
5276 #endif
5277 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5278 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5279 font->potm->otmSize = size;
5281 #define TM font->potm->otmTextMetrics
5282 #ifdef HAVE_FREETYPE_FTWINFNT_H
5283 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5285 TM.tmHeight = winfnt_header.pixel_height;
5286 TM.tmAscent = winfnt_header.ascent;
5287 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5288 TM.tmInternalLeading = winfnt_header.internal_leading;
5289 TM.tmExternalLeading = winfnt_header.external_leading;
5290 TM.tmAveCharWidth = winfnt_header.avg_width;
5291 TM.tmMaxCharWidth = winfnt_header.max_width;
5292 TM.tmWeight = winfnt_header.weight;
5293 TM.tmOverhang = 0;
5294 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5295 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5296 TM.tmFirstChar = winfnt_header.first_char;
5297 TM.tmLastChar = winfnt_header.last_char;
5298 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5299 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5300 TM.tmItalic = winfnt_header.italic;
5301 TM.tmUnderlined = font->underline;
5302 TM.tmStruckOut = font->strikeout;
5303 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5304 TM.tmCharSet = winfnt_header.charset;
5306 else
5307 #endif
5309 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5310 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5311 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5312 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5313 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5314 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5315 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5316 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5317 TM.tmOverhang = 0;
5318 TM.tmDigitizedAspectX = 96; /* FIXME */
5319 TM.tmDigitizedAspectY = 96; /* FIXME */
5320 TM.tmFirstChar = 1;
5321 TM.tmLastChar = 255;
5322 TM.tmDefaultChar = 32;
5323 TM.tmBreakChar = 32;
5324 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5325 TM.tmUnderlined = font->underline;
5326 TM.tmStruckOut = font->strikeout;
5327 /* NB inverted meaning of TMPF_FIXED_PITCH */
5328 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5329 TM.tmCharSet = font->charset;
5331 #undef TM
5333 return TRUE;
5337 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5339 double scale_x, scale_y;
5341 if (font->aveWidth)
5343 scale_x = (double)font->aveWidth;
5344 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5346 else
5347 scale_x = font->scale_y;
5349 scale_x *= fabs(font->font_desc.matrix.eM11);
5350 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5352 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5353 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5355 SCALE_Y(ptm->tmHeight);
5356 SCALE_Y(ptm->tmAscent);
5357 SCALE_Y(ptm->tmDescent);
5358 SCALE_Y(ptm->tmInternalLeading);
5359 SCALE_Y(ptm->tmExternalLeading);
5360 SCALE_Y(ptm->tmOverhang);
5362 SCALE_X(ptm->tmAveCharWidth);
5363 SCALE_X(ptm->tmMaxCharWidth);
5365 #undef SCALE_X
5366 #undef SCALE_Y
5369 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5371 double scale_x, scale_y;
5373 if (font->aveWidth)
5375 scale_x = (double)font->aveWidth;
5376 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5378 else
5379 scale_x = font->scale_y;
5381 scale_x *= fabs(font->font_desc.matrix.eM11);
5382 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5384 scale_font_metrics(font, &potm->otmTextMetrics);
5386 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5387 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5389 SCALE_Y(potm->otmAscent);
5390 SCALE_Y(potm->otmDescent);
5391 SCALE_Y(potm->otmLineGap);
5392 SCALE_Y(potm->otmsCapEmHeight);
5393 SCALE_Y(potm->otmsXHeight);
5394 SCALE_Y(potm->otmrcFontBox.top);
5395 SCALE_Y(potm->otmrcFontBox.bottom);
5396 SCALE_X(potm->otmrcFontBox.left);
5397 SCALE_X(potm->otmrcFontBox.right);
5398 SCALE_Y(potm->otmMacAscent);
5399 SCALE_Y(potm->otmMacDescent);
5400 SCALE_Y(potm->otmMacLineGap);
5401 SCALE_X(potm->otmptSubscriptSize.x);
5402 SCALE_Y(potm->otmptSubscriptSize.y);
5403 SCALE_X(potm->otmptSubscriptOffset.x);
5404 SCALE_Y(potm->otmptSubscriptOffset.y);
5405 SCALE_X(potm->otmptSuperscriptSize.x);
5406 SCALE_Y(potm->otmptSuperscriptSize.y);
5407 SCALE_X(potm->otmptSuperscriptOffset.x);
5408 SCALE_Y(potm->otmptSuperscriptOffset.y);
5409 SCALE_Y(potm->otmsStrikeoutSize);
5410 SCALE_Y(potm->otmsStrikeoutPosition);
5411 SCALE_Y(potm->otmsUnderscoreSize);
5412 SCALE_Y(potm->otmsUnderscorePosition);
5414 #undef SCALE_X
5415 #undef SCALE_Y
5418 /*************************************************************
5419 * WineEngGetTextMetrics
5422 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5424 GDI_CheckNotLock();
5425 EnterCriticalSection( &freetype_cs );
5426 if(!font->potm) {
5427 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5428 if(!get_bitmap_text_metrics(font))
5430 LeaveCriticalSection( &freetype_cs );
5431 return FALSE;
5434 /* Make sure that the font has sane width/height ratio */
5435 if (font->aveWidth)
5437 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5439 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5440 font->aveWidth = 0;
5445 *ptm = font->potm->otmTextMetrics;
5446 scale_font_metrics(font, ptm);
5447 LeaveCriticalSection( &freetype_cs );
5448 return TRUE;
5451 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5453 int i;
5455 for(i = 0; i < ft_face->num_charmaps; i++)
5457 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5458 return TRUE;
5460 return FALSE;
5463 /*************************************************************
5464 * WineEngGetOutlineTextMetrics
5467 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5468 OUTLINETEXTMETRICW *potm)
5470 FT_Face ft_face = font->ft_face;
5471 UINT needed, lenfam, lensty, ret;
5472 TT_OS2 *pOS2;
5473 TT_HoriHeader *pHori;
5474 TT_Postscript *pPost;
5475 FT_Fixed x_scale, y_scale;
5476 WCHAR *family_nameW, *style_nameW;
5477 static const WCHAR spaceW[] = {' ', '\0'};
5478 char *cp;
5479 INT ascent, descent;
5481 TRACE("font=%p\n", font);
5483 if(!FT_IS_SCALABLE(ft_face))
5484 return 0;
5486 GDI_CheckNotLock();
5487 EnterCriticalSection( &freetype_cs );
5489 if(font->potm) {
5490 if(cbSize >= font->potm->otmSize)
5492 memcpy(potm, font->potm, font->potm->otmSize);
5493 scale_outline_font_metrics(font, potm);
5495 LeaveCriticalSection( &freetype_cs );
5496 return font->potm->otmSize;
5500 needed = sizeof(*potm);
5502 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5503 family_nameW = strdupW(font->name);
5505 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5506 * sizeof(WCHAR);
5507 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5508 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5509 style_nameW, lensty/sizeof(WCHAR));
5511 /* These names should be read from the TT name table */
5513 /* length of otmpFamilyName */
5514 needed += lenfam;
5516 /* length of otmpFaceName */
5517 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5518 needed += lenfam; /* just the family name */
5519 } else {
5520 needed += lenfam + lensty; /* family + " " + style */
5523 /* length of otmpStyleName */
5524 needed += lensty;
5526 /* length of otmpFullName */
5527 needed += lenfam + lensty;
5530 x_scale = ft_face->size->metrics.x_scale;
5531 y_scale = ft_face->size->metrics.y_scale;
5533 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5534 if(!pOS2) {
5535 FIXME("Can't find OS/2 table - not TT font?\n");
5536 ret = 0;
5537 goto end;
5540 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5541 if(!pHori) {
5542 FIXME("Can't find HHEA table - not TT font?\n");
5543 ret = 0;
5544 goto end;
5547 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5549 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",
5550 pOS2->usWinAscent, pOS2->usWinDescent,
5551 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5552 ft_face->ascender, ft_face->descender, ft_face->height,
5553 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5554 ft_face->bbox.yMax, ft_face->bbox.yMin);
5556 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5557 font->potm->otmSize = needed;
5559 #define TM font->potm->otmTextMetrics
5561 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5562 ascent = pHori->Ascender;
5563 descent = -pHori->Descender;
5564 } else {
5565 ascent = pOS2->usWinAscent;
5566 descent = pOS2->usWinDescent;
5569 if(font->yMax) {
5570 TM.tmAscent = font->yMax;
5571 TM.tmDescent = -font->yMin;
5572 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5573 } else {
5574 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5575 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5576 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5577 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5580 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5582 /* MSDN says:
5583 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5585 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5586 ((ascent + descent) -
5587 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5589 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5590 if (TM.tmAveCharWidth == 0) {
5591 TM.tmAveCharWidth = 1;
5593 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5594 TM.tmWeight = FW_REGULAR;
5595 if (font->fake_bold)
5596 TM.tmWeight = FW_BOLD;
5597 else
5599 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5601 if (pOS2->usWeightClass > FW_MEDIUM)
5602 TM.tmWeight = pOS2->usWeightClass;
5604 else if (pOS2->usWeightClass <= FW_MEDIUM)
5605 TM.tmWeight = pOS2->usWeightClass;
5607 TM.tmOverhang = 0;
5608 TM.tmDigitizedAspectX = 300;
5609 TM.tmDigitizedAspectY = 300;
5610 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5611 * symbol range to 0 - f0ff
5614 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5616 TM.tmFirstChar = 0;
5617 switch(GetACP())
5619 case 1257: /* Baltic */
5620 TM.tmLastChar = 0xf8fd;
5621 break;
5622 default:
5623 TM.tmLastChar = 0xf0ff;
5625 TM.tmBreakChar = 0x20;
5626 TM.tmDefaultChar = 0x1f;
5628 else
5630 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5631 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5633 if(pOS2->usFirstCharIndex <= 1)
5634 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5635 else if (pOS2->usFirstCharIndex > 0xff)
5636 TM.tmBreakChar = 0x20;
5637 else
5638 TM.tmBreakChar = pOS2->usFirstCharIndex;
5639 TM.tmDefaultChar = TM.tmBreakChar - 1;
5641 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5642 TM.tmUnderlined = font->underline;
5643 TM.tmStruckOut = font->strikeout;
5645 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5646 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5647 (pOS2->version == 0xFFFFU ||
5648 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5649 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5650 else
5651 TM.tmPitchAndFamily = 0;
5653 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5655 case PAN_FAMILY_SCRIPT:
5656 TM.tmPitchAndFamily |= FF_SCRIPT;
5657 break;
5659 case PAN_FAMILY_DECORATIVE:
5660 TM.tmPitchAndFamily |= FF_DECORATIVE;
5661 break;
5663 case PAN_ANY:
5664 case PAN_NO_FIT:
5665 case PAN_FAMILY_TEXT_DISPLAY:
5666 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5667 /* which is clearly not what the panose spec says. */
5668 default:
5669 if(TM.tmPitchAndFamily == 0 || /* fixed */
5670 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5671 TM.tmPitchAndFamily = FF_MODERN;
5672 else
5674 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5676 case PAN_ANY:
5677 case PAN_NO_FIT:
5678 default:
5679 TM.tmPitchAndFamily |= FF_DONTCARE;
5680 break;
5682 case PAN_SERIF_COVE:
5683 case PAN_SERIF_OBTUSE_COVE:
5684 case PAN_SERIF_SQUARE_COVE:
5685 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5686 case PAN_SERIF_SQUARE:
5687 case PAN_SERIF_THIN:
5688 case PAN_SERIF_BONE:
5689 case PAN_SERIF_EXAGGERATED:
5690 case PAN_SERIF_TRIANGLE:
5691 TM.tmPitchAndFamily |= FF_ROMAN;
5692 break;
5694 case PAN_SERIF_NORMAL_SANS:
5695 case PAN_SERIF_OBTUSE_SANS:
5696 case PAN_SERIF_PERP_SANS:
5697 case PAN_SERIF_FLARED:
5698 case PAN_SERIF_ROUNDED:
5699 TM.tmPitchAndFamily |= FF_SWISS;
5700 break;
5703 break;
5706 if(FT_IS_SCALABLE(ft_face))
5707 TM.tmPitchAndFamily |= TMPF_VECTOR;
5709 if(FT_IS_SFNT(ft_face))
5711 if (font->ntmFlags & NTM_PS_OPENTYPE)
5712 TM.tmPitchAndFamily |= TMPF_DEVICE;
5713 else
5714 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5717 TM.tmCharSet = font->charset;
5719 font->potm->otmFiller = 0;
5720 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5721 font->potm->otmfsSelection = pOS2->fsSelection;
5722 font->potm->otmfsType = pOS2->fsType;
5723 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5724 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5725 font->potm->otmItalicAngle = 0; /* POST table */
5726 font->potm->otmEMSquare = ft_face->units_per_EM;
5727 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5728 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5729 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5730 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5731 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5732 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5733 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5734 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5735 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5736 font->potm->otmMacAscent = TM.tmAscent;
5737 font->potm->otmMacDescent = -TM.tmDescent;
5738 font->potm->otmMacLineGap = font->potm->otmLineGap;
5739 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5740 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5741 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5742 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5743 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5744 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5745 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5746 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5747 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5748 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5749 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5750 if(!pPost) {
5751 font->potm->otmsUnderscoreSize = 0;
5752 font->potm->otmsUnderscorePosition = 0;
5753 } else {
5754 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5755 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5757 #undef TM
5759 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5760 cp = (char*)font->potm + sizeof(*font->potm);
5761 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5762 strcpyW((WCHAR*)cp, family_nameW);
5763 cp += lenfam;
5764 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5765 strcpyW((WCHAR*)cp, style_nameW);
5766 cp += lensty;
5767 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5768 strcpyW((WCHAR*)cp, family_nameW);
5769 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5770 strcatW((WCHAR*)cp, spaceW);
5771 strcatW((WCHAR*)cp, style_nameW);
5772 cp += lenfam + lensty;
5773 } else
5774 cp += lenfam;
5775 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5776 strcpyW((WCHAR*)cp, family_nameW);
5777 strcatW((WCHAR*)cp, spaceW);
5778 strcatW((WCHAR*)cp, style_nameW);
5779 ret = needed;
5781 if(potm && needed <= cbSize)
5783 memcpy(potm, font->potm, font->potm->otmSize);
5784 scale_outline_font_metrics(font, potm);
5787 end:
5788 HeapFree(GetProcessHeap(), 0, style_nameW);
5789 HeapFree(GetProcessHeap(), 0, family_nameW);
5791 LeaveCriticalSection( &freetype_cs );
5792 return ret;
5795 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5797 HFONTLIST *hfontlist;
5798 child->font = alloc_font();
5799 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5800 if(!child->font->ft_face)
5802 free_font(child->font);
5803 child->font = NULL;
5804 return FALSE;
5807 child->font->font_desc = font->font_desc;
5808 child->font->ntmFlags = child->face->ntmFlags;
5809 child->font->orientation = font->orientation;
5810 child->font->scale_y = font->scale_y;
5811 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5812 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5813 child->font->name = strdupW(child->face->family->FamilyName);
5814 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5815 child->font->base_font = font;
5816 list_add_head(&child_font_list, &child->font->entry);
5817 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5818 return TRUE;
5821 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5823 FT_UInt g;
5824 CHILD_FONT *child_font;
5826 if(font->base_font)
5827 font = font->base_font;
5829 *linked_font = font;
5831 if((*glyph = get_glyph_index(font, c)))
5832 return TRUE;
5834 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5836 if(!child_font->font)
5837 if(!load_child_font(font, child_font))
5838 continue;
5840 if(!child_font->font->ft_face)
5841 continue;
5842 g = get_glyph_index(child_font->font, c);
5843 if(g)
5845 *glyph = g;
5846 *linked_font = child_font->font;
5847 return TRUE;
5850 return FALSE;
5853 /*************************************************************
5854 * WineEngGetCharWidth
5857 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5858 LPINT buffer)
5860 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5861 UINT c;
5862 GLYPHMETRICS gm;
5863 FT_UInt glyph_index;
5864 GdiFont *linked_font;
5866 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5868 GDI_CheckNotLock();
5869 EnterCriticalSection( &freetype_cs );
5870 for(c = firstChar; c <= lastChar; c++) {
5871 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5872 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5873 &gm, 0, NULL, &identity);
5874 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5876 LeaveCriticalSection( &freetype_cs );
5877 return TRUE;
5880 /*************************************************************
5881 * WineEngGetCharABCWidths
5884 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5885 LPABC buffer)
5887 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5888 UINT c;
5889 GLYPHMETRICS gm;
5890 FT_UInt glyph_index;
5891 GdiFont *linked_font;
5893 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5895 if(!FT_IS_SCALABLE(font->ft_face))
5896 return FALSE;
5898 GDI_CheckNotLock();
5899 EnterCriticalSection( &freetype_cs );
5901 for(c = firstChar; c <= lastChar; c++) {
5902 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5903 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5904 &gm, 0, NULL, &identity);
5905 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5906 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5907 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5908 FONT_GM(linked_font,glyph_index)->bbx;
5910 LeaveCriticalSection( &freetype_cs );
5911 return TRUE;
5914 /*************************************************************
5915 * WineEngGetCharABCWidthsI
5918 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5919 LPABC buffer)
5921 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5922 UINT c;
5923 GLYPHMETRICS gm;
5924 FT_UInt glyph_index;
5925 GdiFont *linked_font;
5927 if(!FT_HAS_HORIZONTAL(font->ft_face))
5928 return FALSE;
5930 GDI_CheckNotLock();
5931 EnterCriticalSection( &freetype_cs );
5933 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5934 if (!pgi)
5935 for(c = firstChar; c < firstChar+count; c++) {
5936 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5937 &gm, 0, NULL, &identity);
5938 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5939 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5940 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5941 - FONT_GM(linked_font,c)->bbx;
5943 else
5944 for(c = 0; c < count; c++) {
5945 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5946 &gm, 0, NULL, &identity);
5947 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5948 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5949 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5950 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5953 LeaveCriticalSection( &freetype_cs );
5954 return TRUE;
5957 /*************************************************************
5958 * WineEngGetTextExtentExPoint
5961 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5962 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5964 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5965 INT idx;
5966 INT nfit = 0, ext;
5967 GLYPHMETRICS gm;
5968 TEXTMETRICW tm;
5969 FT_UInt glyph_index;
5970 GdiFont *linked_font;
5972 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5973 max_ext, size);
5975 GDI_CheckNotLock();
5976 EnterCriticalSection( &freetype_cs );
5978 size->cx = 0;
5979 WineEngGetTextMetrics(font, &tm);
5980 size->cy = tm.tmHeight;
5982 for(idx = 0; idx < count; idx++) {
5983 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5984 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5985 &gm, 0, NULL, &identity);
5986 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5987 ext = size->cx;
5988 if (! pnfit || ext <= max_ext) {
5989 ++nfit;
5990 if (dxs)
5991 dxs[idx] = ext;
5995 if (pnfit)
5996 *pnfit = nfit;
5998 LeaveCriticalSection( &freetype_cs );
5999 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6000 return TRUE;
6003 /*************************************************************
6004 * WineEngGetTextExtentExPointI
6007 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6008 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6010 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6011 INT idx;
6012 INT nfit = 0, ext;
6013 GLYPHMETRICS gm;
6014 TEXTMETRICW tm;
6016 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6018 GDI_CheckNotLock();
6019 EnterCriticalSection( &freetype_cs );
6021 size->cx = 0;
6022 WineEngGetTextMetrics(font, &tm);
6023 size->cy = tm.tmHeight;
6025 for(idx = 0; idx < count; idx++) {
6026 WineEngGetGlyphOutline(font, indices[idx],
6027 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6028 &identity);
6029 size->cx += FONT_GM(font,indices[idx])->adv;
6030 ext = size->cx;
6031 if (! pnfit || ext <= max_ext) {
6032 ++nfit;
6033 if (dxs)
6034 dxs[idx] = ext;
6038 if (pnfit)
6039 *pnfit = nfit;
6041 LeaveCriticalSection( &freetype_cs );
6042 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6043 return TRUE;
6046 /*************************************************************
6047 * WineEngGetFontData
6050 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6051 DWORD cbData)
6053 FT_Face ft_face = font->ft_face;
6054 FT_ULong len;
6055 FT_Error err;
6057 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6058 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6059 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6061 if(!FT_IS_SFNT(ft_face))
6062 return GDI_ERROR;
6064 if(!buf || !cbData)
6065 len = 0;
6066 else
6067 len = cbData;
6069 if(table) { /* MS tags differ in endianness from FT ones */
6070 table = table >> 24 | table << 24 |
6071 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6074 /* make sure value of len is the value freetype says it needs */
6075 if(buf && len)
6077 FT_ULong needed = 0;
6078 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6079 if( !err && needed < len) len = needed;
6081 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6083 if(err) {
6084 TRACE("Can't find table %c%c%c%c\n",
6085 /* bytes were reversed */
6086 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6087 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6088 return GDI_ERROR;
6090 return len;
6093 /*************************************************************
6094 * WineEngGetTextFace
6097 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6099 INT n = strlenW(font->name) + 1;
6100 if(str) {
6101 lstrcpynW(str, font->name, count);
6102 return min(count, n);
6103 } else
6104 return n;
6107 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6109 if (fs) *fs = font->fs;
6110 return font->charset;
6113 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6115 GdiFont *font = dc->gdiFont, *linked_font;
6116 struct list *first_hfont;
6117 BOOL ret;
6119 GDI_CheckNotLock();
6120 EnterCriticalSection( &freetype_cs );
6121 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6122 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6123 if(font == linked_font)
6124 *new_hfont = dc->hFont;
6125 else
6127 first_hfont = list_head(&linked_font->hfontlist);
6128 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6130 LeaveCriticalSection( &freetype_cs );
6131 return ret;
6134 /* Retrieve a list of supported Unicode ranges for a given font.
6135 * Can be called with NULL gs to calculate the buffer size. Returns
6136 * the number of ranges found.
6138 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6140 DWORD num_ranges = 0;
6142 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6144 FT_UInt glyph_code;
6145 FT_ULong char_code, char_code_prev;
6147 glyph_code = 0;
6148 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6150 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6151 face->num_glyphs, glyph_code, char_code);
6153 if (!glyph_code) return 0;
6155 if (gs)
6157 gs->ranges[0].wcLow = (USHORT)char_code;
6158 gs->ranges[0].cGlyphs = 0;
6159 gs->cGlyphsSupported = 0;
6162 num_ranges = 1;
6163 while (glyph_code)
6165 if (char_code < char_code_prev)
6167 ERR("expected increasing char code from FT_Get_Next_Char\n");
6168 return 0;
6170 if (char_code - char_code_prev > 1)
6172 num_ranges++;
6173 if (gs)
6175 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6176 gs->ranges[num_ranges - 1].cGlyphs = 1;
6177 gs->cGlyphsSupported++;
6180 else if (gs)
6182 gs->ranges[num_ranges - 1].cGlyphs++;
6183 gs->cGlyphsSupported++;
6185 char_code_prev = char_code;
6186 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6189 else
6190 FIXME("encoding %u not supported\n", face->charmap->encoding);
6192 return num_ranges;
6195 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6197 DWORD size = 0;
6198 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6200 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6201 if (glyphset)
6203 glyphset->cbThis = size;
6204 glyphset->cRanges = num_ranges;
6206 return size;
6209 /*************************************************************
6210 * FontIsLinked
6212 BOOL WineEngFontIsLinked(GdiFont *font)
6214 BOOL ret;
6215 GDI_CheckNotLock();
6216 EnterCriticalSection( &freetype_cs );
6217 ret = !list_empty(&font->child_fonts);
6218 LeaveCriticalSection( &freetype_cs );
6219 return ret;
6222 static BOOL is_hinting_enabled(void)
6224 /* Use the >= 2.2.0 function if available */
6225 if(pFT_Get_TrueType_Engine_Type)
6227 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6228 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6230 #ifdef FT_DRIVER_HAS_HINTER
6231 else
6233 FT_Module mod;
6235 /* otherwise if we've been compiled with < 2.2.0 headers
6236 use the internal macro */
6237 mod = pFT_Get_Module(library, "truetype");
6238 if(mod && FT_DRIVER_HAS_HINTER(mod))
6239 return TRUE;
6241 #endif
6243 return FALSE;
6246 static BOOL is_subpixel_rendering_enabled( void )
6248 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6249 return pFT_Library_SetLcdFilter &&
6250 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6251 #else
6252 return FALSE;
6253 #endif
6256 /*************************************************************************
6257 * GetRasterizerCaps (GDI32.@)
6259 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6261 static int hinting = -1;
6262 static int subpixel = -1;
6264 if(hinting == -1)
6266 hinting = is_hinting_enabled();
6267 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6270 if ( subpixel == -1 )
6272 subpixel = is_subpixel_rendering_enabled();
6273 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6276 lprs->nSize = sizeof(RASTERIZER_STATUS);
6277 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6278 if ( subpixel )
6279 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6280 lprs->nLanguageID = 0;
6281 return TRUE;
6284 /*************************************************************
6285 * WineEngRealizationInfo
6287 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6289 FIXME("(%p, %p): stub!\n", font, info);
6291 info->flags = 1;
6292 if(FT_IS_SCALABLE(font->ft_face))
6293 info->flags |= 2;
6295 info->cache_num = font->cache_num;
6296 info->unknown2 = -1;
6297 return TRUE;
6300 /*************************************************************************
6301 * Kerning support for TrueType fonts
6303 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6305 struct TT_kern_table
6307 USHORT version;
6308 USHORT nTables;
6311 struct TT_kern_subtable
6313 USHORT version;
6314 USHORT length;
6315 union
6317 USHORT word;
6318 struct
6320 USHORT horizontal : 1;
6321 USHORT minimum : 1;
6322 USHORT cross_stream: 1;
6323 USHORT override : 1;
6324 USHORT reserved1 : 4;
6325 USHORT format : 8;
6326 } bits;
6327 } coverage;
6330 struct TT_format0_kern_subtable
6332 USHORT nPairs;
6333 USHORT searchRange;
6334 USHORT entrySelector;
6335 USHORT rangeShift;
6338 struct TT_kern_pair
6340 USHORT left;
6341 USHORT right;
6342 short value;
6345 static DWORD parse_format0_kern_subtable(GdiFont *font,
6346 const struct TT_format0_kern_subtable *tt_f0_ks,
6347 const USHORT *glyph_to_char,
6348 KERNINGPAIR *kern_pair, DWORD cPairs)
6350 USHORT i, nPairs;
6351 const struct TT_kern_pair *tt_kern_pair;
6353 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6355 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6357 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6358 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6359 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6361 if (!kern_pair || !cPairs)
6362 return nPairs;
6364 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6366 nPairs = min(nPairs, cPairs);
6368 for (i = 0; i < nPairs; i++)
6370 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6371 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6372 /* this algorithm appears to better match what Windows does */
6373 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6374 if (kern_pair->iKernAmount < 0)
6376 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6377 kern_pair->iKernAmount -= font->ppem;
6379 else if (kern_pair->iKernAmount > 0)
6381 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6382 kern_pair->iKernAmount += font->ppem;
6384 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6386 TRACE("left %u right %u value %d\n",
6387 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6389 kern_pair++;
6391 TRACE("copied %u entries\n", nPairs);
6392 return nPairs;
6395 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6397 DWORD length;
6398 void *buf;
6399 const struct TT_kern_table *tt_kern_table;
6400 const struct TT_kern_subtable *tt_kern_subtable;
6401 USHORT i, nTables;
6402 USHORT *glyph_to_char;
6404 GDI_CheckNotLock();
6405 EnterCriticalSection( &freetype_cs );
6406 if (font->total_kern_pairs != (DWORD)-1)
6408 if (cPairs && kern_pair)
6410 cPairs = min(cPairs, font->total_kern_pairs);
6411 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6412 LeaveCriticalSection( &freetype_cs );
6413 return cPairs;
6415 LeaveCriticalSection( &freetype_cs );
6416 return font->total_kern_pairs;
6419 font->total_kern_pairs = 0;
6421 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6423 if (length == GDI_ERROR)
6425 TRACE("no kerning data in the font\n");
6426 LeaveCriticalSection( &freetype_cs );
6427 return 0;
6430 buf = HeapAlloc(GetProcessHeap(), 0, length);
6431 if (!buf)
6433 WARN("Out of memory\n");
6434 LeaveCriticalSection( &freetype_cs );
6435 return 0;
6438 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6440 /* build a glyph index to char code map */
6441 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6442 if (!glyph_to_char)
6444 WARN("Out of memory allocating a glyph index to char code map\n");
6445 HeapFree(GetProcessHeap(), 0, buf);
6446 LeaveCriticalSection( &freetype_cs );
6447 return 0;
6450 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6452 FT_UInt glyph_code;
6453 FT_ULong char_code;
6455 glyph_code = 0;
6456 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6458 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6459 font->ft_face->num_glyphs, glyph_code, char_code);
6461 while (glyph_code)
6463 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6465 /* FIXME: This doesn't match what Windows does: it does some fancy
6466 * things with duplicate glyph index to char code mappings, while
6467 * we just avoid overriding existing entries.
6469 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6470 glyph_to_char[glyph_code] = (USHORT)char_code;
6472 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6475 else
6477 ULONG n;
6479 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6480 for (n = 0; n <= 65535; n++)
6481 glyph_to_char[n] = (USHORT)n;
6484 tt_kern_table = buf;
6485 nTables = GET_BE_WORD(tt_kern_table->nTables);
6486 TRACE("version %u, nTables %u\n",
6487 GET_BE_WORD(tt_kern_table->version), nTables);
6489 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6491 for (i = 0; i < nTables; i++)
6493 struct TT_kern_subtable tt_kern_subtable_copy;
6495 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6496 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6497 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6499 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6500 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6501 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6503 /* According to the TrueType specification this is the only format
6504 * that will be properly interpreted by Windows and OS/2
6506 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6508 DWORD new_chunk, old_total = font->total_kern_pairs;
6510 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6511 glyph_to_char, NULL, 0);
6512 font->total_kern_pairs += new_chunk;
6514 if (!font->kern_pairs)
6515 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6516 font->total_kern_pairs * sizeof(*font->kern_pairs));
6517 else
6518 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6519 font->total_kern_pairs * sizeof(*font->kern_pairs));
6521 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6522 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6524 else
6525 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6527 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6530 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6531 HeapFree(GetProcessHeap(), 0, buf);
6533 if (cPairs && kern_pair)
6535 cPairs = min(cPairs, font->total_kern_pairs);
6536 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6537 LeaveCriticalSection( &freetype_cs );
6538 return cPairs;
6540 LeaveCriticalSection( &freetype_cs );
6541 return font->total_kern_pairs;
6544 #else /* HAVE_FREETYPE */
6546 /*************************************************************************/
6548 BOOL WineEngInit(void)
6550 return FALSE;
6552 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6554 return NULL;
6556 BOOL WineEngDestroyFontInstance(HFONT hfont)
6558 return FALSE;
6561 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6563 return 1;
6566 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6567 LPWORD pgi, DWORD flags)
6569 return GDI_ERROR;
6572 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6573 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6574 const MAT2* lpmat)
6576 ERR("called but we don't have FreeType\n");
6577 return GDI_ERROR;
6580 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6582 ERR("called but we don't have FreeType\n");
6583 return FALSE;
6586 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6587 OUTLINETEXTMETRICW *potm)
6589 ERR("called but we don't have FreeType\n");
6590 return 0;
6593 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6594 LPINT buffer)
6596 ERR("called but we don't have FreeType\n");
6597 return FALSE;
6600 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6601 LPABC buffer)
6603 ERR("called but we don't have FreeType\n");
6604 return FALSE;
6607 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6608 LPABC buffer)
6610 ERR("called but we don't have FreeType\n");
6611 return FALSE;
6614 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6615 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6617 ERR("called but we don't have FreeType\n");
6618 return FALSE;
6621 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6622 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6624 ERR("called but we don't have FreeType\n");
6625 return FALSE;
6628 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6629 DWORD cbData)
6631 ERR("called but we don't have FreeType\n");
6632 return GDI_ERROR;
6635 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6637 ERR("called but we don't have FreeType\n");
6638 return 0;
6641 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6643 FIXME(":stub\n");
6644 return 1;
6647 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6649 FIXME(":stub\n");
6650 return TRUE;
6653 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6655 FIXME(":stub\n");
6656 return NULL;
6659 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6661 FIXME(":stub\n");
6662 return DEFAULT_CHARSET;
6665 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6667 return FALSE;
6670 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6672 FIXME("(%p, %p): stub\n", font, glyphset);
6673 return 0;
6676 BOOL WineEngFontIsLinked(GdiFont *font)
6678 return FALSE;
6681 /*************************************************************************
6682 * GetRasterizerCaps (GDI32.@)
6684 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6686 lprs->nSize = sizeof(RASTERIZER_STATUS);
6687 lprs->wFlags = 0;
6688 lprs->nLanguageID = 0;
6689 return TRUE;
6692 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6694 ERR("called but we don't have FreeType\n");
6695 return 0;
6698 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6700 ERR("called but we don't have FreeType\n");
6701 return FALSE;
6704 #endif /* HAVE_FREETYPE */