gdi32: Move charset enumeration to helper function.
[wine.git] / dlls / gdi32 / freetype.c
blob31fe4f2ec10c964d0dc8cbcbe9638160a315bb41
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
94 #ifdef HAVE_FREETYPE
96 #ifdef HAVE_FT2BUILD_H
97 #include <ft2build.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
101 #endif
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
104 #endif
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
110 #endif
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
113 #endif
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
116 #endif
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
119 #endif
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
122 #endif
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
134 #endif
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 typedef enum
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
143 #endif
145 static FT_Library library = 0;
146 typedef struct
148 FT_Int major;
149 FT_Int minor;
150 FT_Int patch;
151 } FT_Version_t;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
170 #else
171 MAKE_FUNCPTR(FT_MulFix);
172 #endif
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
193 #endif
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
208 #endif
210 #undef MAKE_FUNCPTR
212 #ifndef FT_MAKE_TAG
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #endif
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
220 #endif
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
223 #endif
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
226 #endif
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #endif
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
233 #else
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 #endif
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
238 typedef struct {
239 FT_Short height;
240 FT_Short width;
241 FT_Pos size;
242 FT_Pos x_ppem;
243 FT_Pos y_ppem;
244 FT_Short internal_leading;
245 } Bitmap_Size;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
250 typedef struct {
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
253 } My_FT_Bitmap_Size;
255 struct enum_data
257 ENUMLOGFONTEXW elf;
258 NEWTEXTMETRICEXW ntm;
259 DWORD type;
262 typedef struct tagFace {
263 struct list entry;
264 WCHAR *StyleName;
265 char *file;
266 void *font_data_ptr;
267 DWORD font_data_size;
268 FT_Long face_index;
269 FONTSIGNATURE fs;
270 FONTSIGNATURE fs_links;
271 DWORD ntmFlags;
272 FT_Fixed font_version;
273 BOOL scalable;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
279 } Face;
281 typedef struct tagFamily {
282 struct list entry;
283 const WCHAR *FamilyName;
284 struct list faces;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 struct list links;
355 } SYSTEM_LINKS;
357 #define GM_BLOCK_SIZE 128
358 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
360 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
361 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
362 #define UNUSED_CACHE_SIZE 10
363 static struct list child_font_list = LIST_INIT(child_font_list);
364 static struct list system_links = LIST_INIT(system_links);
366 static struct list font_subst_list = LIST_INIT(font_subst_list);
368 static struct list font_list = LIST_INIT(font_list);
370 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
371 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
372 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
374 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
375 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
376 'W','i','n','d','o','w','s','\\',
377 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
378 'F','o','n','t','s','\0'};
380 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
381 'W','i','n','d','o','w','s',' ','N','T','\\',
382 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
383 'F','o','n','t','s','\0'};
385 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
386 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
387 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
388 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
390 static const WCHAR * const SystemFontValues[4] = {
391 System_Value,
392 OEMFont_Value,
393 FixedSys_Value,
394 NULL
397 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
398 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
400 /* Interesting and well-known (frequently-assumed!) font names */
401 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
402 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
403 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
404 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
405 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
406 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
407 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
408 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
410 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
411 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
412 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
413 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
414 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
415 'E','u','r','o','p','e','a','n','\0'};
416 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
417 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
418 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
419 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
420 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
421 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
422 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
423 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
424 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
425 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
426 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
427 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
429 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
430 WesternW, /*00*/
431 Central_EuropeanW,
432 CyrillicW,
433 GreekW,
434 TurkishW,
435 HebrewW,
436 ArabicW,
437 BalticW,
438 VietnameseW, /*08*/
439 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
440 ThaiW,
441 JapaneseW,
442 CHINESE_GB2312W,
443 HangulW,
444 CHINESE_BIG5W,
445 Hangul_Johab_W,
446 NULL, NULL, /*23*/
447 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
448 SymbolW /*31*/
451 typedef struct {
452 WCHAR *name;
453 INT charset;
454 } NameCs;
456 typedef struct tagFontSubst {
457 struct list entry;
458 NameCs from;
459 NameCs to;
460 } FontSubst;
462 struct font_mapping
464 struct list entry;
465 int refcount;
466 dev_t dev;
467 ino_t ino;
468 void *data;
469 size_t size;
472 static struct list mappings_list = LIST_INIT( mappings_list );
474 static CRITICAL_SECTION freetype_cs;
475 static CRITICAL_SECTION_DEBUG critsect_debug =
477 0, 0, &freetype_cs,
478 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
479 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
481 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
483 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
485 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
486 static BOOL use_default_fallback = FALSE;
488 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
490 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
491 'W','i','n','d','o','w','s',' ','N','T','\\',
492 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
493 'S','y','s','t','e','m','L','i','n','k',0};
495 /****************************************
496 * Notes on .fon files
498 * The fonts System, FixedSys and Terminal are special. There are typically multiple
499 * versions installed for different resolutions and codepages. Windows stores which one to use
500 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
501 * Key Meaning
502 * FIXEDFON.FON FixedSys
503 * FONTS.FON System
504 * OEMFONT.FON Terminal
505 * LogPixels Current dpi set by the display control panel applet
506 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
507 * also has a LogPixels value that appears to mirror this)
509 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
510 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
511 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
512 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
513 * so that makes sense.
515 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
516 * to be mapped into the registry on Windows 2000 at least).
517 * I have
518 * woafont=app850.fon
519 * ega80woa.fon=ega80850.fon
520 * ega40woa.fon=ega40850.fon
521 * cga80woa.fon=cga80850.fon
522 * cga40woa.fon=cga40850.fon
525 /* These are all structures needed for the GSUB table */
527 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
528 #define TATEGAKI_LOWER_BOUND 0x02F1
530 typedef struct {
531 DWORD version;
532 WORD ScriptList;
533 WORD FeatureList;
534 WORD LookupList;
535 } GSUB_Header;
537 typedef struct {
538 CHAR ScriptTag[4];
539 WORD Script;
540 } GSUB_ScriptRecord;
542 typedef struct {
543 WORD ScriptCount;
544 GSUB_ScriptRecord ScriptRecord[1];
545 } GSUB_ScriptList;
547 typedef struct {
548 CHAR LangSysTag[4];
549 WORD LangSys;
550 } GSUB_LangSysRecord;
552 typedef struct {
553 WORD DefaultLangSys;
554 WORD LangSysCount;
555 GSUB_LangSysRecord LangSysRecord[1];
556 } GSUB_Script;
558 typedef struct {
559 WORD LookupOrder; /* Reserved */
560 WORD ReqFeatureIndex;
561 WORD FeatureCount;
562 WORD FeatureIndex[1];
563 } GSUB_LangSys;
565 typedef struct {
566 CHAR FeatureTag[4];
567 WORD Feature;
568 } GSUB_FeatureRecord;
570 typedef struct {
571 WORD FeatureCount;
572 GSUB_FeatureRecord FeatureRecord[1];
573 } GSUB_FeatureList;
575 typedef struct {
576 WORD FeatureParams; /* Reserved */
577 WORD LookupCount;
578 WORD LookupListIndex[1];
579 } GSUB_Feature;
581 typedef struct {
582 WORD LookupCount;
583 WORD Lookup[1];
584 } GSUB_LookupList;
586 typedef struct {
587 WORD LookupType;
588 WORD LookupFlag;
589 WORD SubTableCount;
590 WORD SubTable[1];
591 } GSUB_LookupTable;
593 typedef struct {
594 WORD CoverageFormat;
595 WORD GlyphCount;
596 WORD GlyphArray[1];
597 } GSUB_CoverageFormat1;
599 typedef struct {
600 WORD Start;
601 WORD End;
602 WORD StartCoverageIndex;
603 } GSUB_RangeRecord;
605 typedef struct {
606 WORD CoverageFormat;
607 WORD RangeCount;
608 GSUB_RangeRecord RangeRecord[1];
609 } GSUB_CoverageFormat2;
611 typedef struct {
612 WORD SubstFormat; /* = 1 */
613 WORD Coverage;
614 WORD DeltaGlyphID;
615 } GSUB_SingleSubstFormat1;
617 typedef struct {
618 WORD SubstFormat; /* = 2 */
619 WORD Coverage;
620 WORD GlyphCount;
621 WORD Substitute[1];
622 }GSUB_SingleSubstFormat2;
624 #ifdef HAVE_CARBON_CARBON_H
625 static char *find_cache_dir(void)
627 FSRef ref;
628 OSErr err;
629 static char cached_path[MAX_PATH];
630 static const char *wine = "/Wine", *fonts = "/Fonts";
632 if(*cached_path) return cached_path;
634 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
635 if(err != noErr)
637 WARN("can't create cached data folder\n");
638 return NULL;
640 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
641 if(err != noErr)
643 WARN("can't create cached data path\n");
644 *cached_path = '\0';
645 return NULL;
647 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
649 ERR("Could not create full path\n");
650 *cached_path = '\0';
651 return NULL;
653 strcat(cached_path, wine);
655 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
657 WARN("Couldn't mkdir %s\n", cached_path);
658 *cached_path = '\0';
659 return NULL;
661 strcat(cached_path, fonts);
662 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
664 WARN("Couldn't mkdir %s\n", cached_path);
665 *cached_path = '\0';
666 return NULL;
668 return cached_path;
671 /******************************************************************
672 * expand_mac_font
674 * Extracts individual TrueType font files from a Mac suitcase font
675 * and saves them into the user's caches directory (see
676 * find_cache_dir()).
677 * Returns a NULL terminated array of filenames.
679 * We do this because they are apps that try to read ttf files
680 * themselves and they don't like Mac suitcase files.
682 static char **expand_mac_font(const char *path)
684 FSRef ref;
685 SInt16 res_ref;
686 OSStatus s;
687 unsigned int idx;
688 const char *out_dir;
689 const char *filename;
690 int output_len;
691 struct {
692 char **array;
693 unsigned int size, max_size;
694 } ret;
696 TRACE("path %s\n", path);
698 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
699 if(s != noErr)
701 WARN("failed to get ref\n");
702 return NULL;
705 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
706 if(s != noErr)
708 TRACE("no data fork, so trying resource fork\n");
709 res_ref = FSOpenResFile(&ref, fsRdPerm);
710 if(res_ref == -1)
712 TRACE("unable to open resource fork\n");
713 return NULL;
717 ret.size = 0;
718 ret.max_size = 10;
719 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
720 if(!ret.array)
722 CloseResFile(res_ref);
723 return NULL;
726 out_dir = find_cache_dir();
728 filename = strrchr(path, '/');
729 if(!filename) filename = path;
730 else filename++;
732 /* output filename has the form out_dir/filename_%04x.ttf */
733 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
735 UseResFile(res_ref);
736 idx = 1;
737 while(1)
739 FamRec *fam_rec;
740 unsigned short *num_faces_ptr, num_faces, face;
741 AsscEntry *assoc;
742 Handle fond;
743 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
745 fond = Get1IndResource(fond_res, idx);
746 if(!fond) break;
747 TRACE("got fond resource %d\n", idx);
748 HLock(fond);
750 fam_rec = *(FamRec**)fond;
751 num_faces_ptr = (unsigned short *)(fam_rec + 1);
752 num_faces = GET_BE_WORD(*num_faces_ptr);
753 num_faces++;
754 assoc = (AsscEntry*)(num_faces_ptr + 1);
755 TRACE("num faces %04x\n", num_faces);
756 for(face = 0; face < num_faces; face++, assoc++)
758 Handle sfnt;
759 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
760 unsigned short size, font_id;
761 char *output;
763 size = GET_BE_WORD(assoc->fontSize);
764 font_id = GET_BE_WORD(assoc->fontID);
765 if(size != 0)
767 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
768 continue;
771 TRACE("trying to load sfnt id %04x\n", font_id);
772 sfnt = GetResource(sfnt_res, font_id);
773 if(!sfnt)
775 TRACE("can't get sfnt resource %04x\n", font_id);
776 continue;
779 output = HeapAlloc(GetProcessHeap(), 0, output_len);
780 if(output)
782 int fd;
784 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
786 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
787 if(fd != -1 || errno == EEXIST)
789 if(fd != -1)
791 unsigned char *sfnt_data;
793 HLock(sfnt);
794 sfnt_data = *(unsigned char**)sfnt;
795 write(fd, sfnt_data, GetHandleSize(sfnt));
796 HUnlock(sfnt);
797 close(fd);
799 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
801 ret.max_size *= 2;
802 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
804 ret.array[ret.size++] = output;
806 else
808 WARN("unable to create %s\n", output);
809 HeapFree(GetProcessHeap(), 0, output);
812 ReleaseResource(sfnt);
814 HUnlock(fond);
815 ReleaseResource(fond);
816 idx++;
818 CloseResFile(res_ref);
820 return ret.array;
823 #endif /* HAVE_CARBON_CARBON_H */
825 static inline BOOL is_win9x(void)
827 return GetVersion() & 0x80000000;
830 This function builds an FT_Fixed from a double. It fails if the absolute
831 value of the float number is greater than 32768.
833 static inline FT_Fixed FT_FixedFromFloat(double f)
835 return f * 0x10000;
839 This function builds an FT_Fixed from a FIXED. It simply put f.value
840 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
842 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
844 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
848 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
850 Family *family;
851 Face *face;
852 const char *file;
853 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
854 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
856 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
857 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
859 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
861 if(face_name && strcmpiW(face_name, family->FamilyName))
862 continue;
863 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
865 if (!face->file)
866 continue;
867 file = strrchr(face->file, '/');
868 if(!file)
869 file = face->file;
870 else
871 file++;
872 if(!strcasecmp(file, file_nameA))
874 HeapFree(GetProcessHeap(), 0, file_nameA);
875 return face;
879 HeapFree(GetProcessHeap(), 0, file_nameA);
880 return NULL;
883 static Family *find_family_from_name(const WCHAR *name)
885 Family *family;
887 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
889 if(!strcmpiW(family->FamilyName, name))
890 return family;
893 return NULL;
896 static void DumpSubstList(void)
898 FontSubst *psub;
900 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
902 if(psub->from.charset != -1 || psub->to.charset != -1)
903 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
904 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
905 else
906 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
907 debugstr_w(psub->to.name));
909 return;
912 static LPWSTR strdupW(LPCWSTR p)
914 LPWSTR ret;
915 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
916 ret = HeapAlloc(GetProcessHeap(), 0, len);
917 memcpy(ret, p, len);
918 return ret;
921 static LPSTR strdupA(LPCSTR p)
923 LPSTR ret;
924 DWORD len = (strlen(p) + 1);
925 ret = HeapAlloc(GetProcessHeap(), 0, len);
926 memcpy(ret, p, len);
927 return ret;
930 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
931 INT from_charset)
933 FontSubst *element;
935 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
937 if(!strcmpiW(element->from.name, from_name) &&
938 (element->from.charset == from_charset ||
939 element->from.charset == -1))
940 return element;
943 return NULL;
946 #define ADD_FONT_SUBST_FORCE 1
948 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
950 FontSubst *from_exist, *to_exist;
952 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
954 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
956 list_remove(&from_exist->entry);
957 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
958 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
959 HeapFree(GetProcessHeap(), 0, from_exist);
960 from_exist = NULL;
963 if(!from_exist)
965 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
967 if(to_exist)
969 HeapFree(GetProcessHeap(), 0, subst->to.name);
970 subst->to.name = strdupW(to_exist->to.name);
973 list_add_tail(subst_list, &subst->entry);
975 return TRUE;
978 HeapFree(GetProcessHeap(), 0, subst->from.name);
979 HeapFree(GetProcessHeap(), 0, subst->to.name);
980 HeapFree(GetProcessHeap(), 0, subst);
981 return FALSE;
984 static void split_subst_info(NameCs *nc, LPSTR str)
986 CHAR *p = strrchr(str, ',');
987 DWORD len;
989 nc->charset = -1;
990 if(p && *(p+1)) {
991 nc->charset = strtol(p+1, NULL, 10);
992 *p = '\0';
994 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
995 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
996 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
999 static void LoadSubstList(void)
1001 FontSubst *psub;
1002 HKEY hkey;
1003 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1004 LPSTR value;
1005 LPVOID data;
1007 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1008 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1009 &hkey) == ERROR_SUCCESS) {
1011 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1012 &valuelen, &datalen, NULL, NULL);
1014 valuelen++; /* returned value doesn't include room for '\0' */
1015 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1016 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1018 dlen = datalen;
1019 vlen = valuelen;
1020 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1021 &dlen) == ERROR_SUCCESS) {
1022 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1024 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1025 split_subst_info(&psub->from, value);
1026 split_subst_info(&psub->to, data);
1028 /* Win 2000 doesn't allow mapping between different charsets
1029 or mapping of DEFAULT_CHARSET */
1030 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1031 psub->to.charset == DEFAULT_CHARSET) {
1032 HeapFree(GetProcessHeap(), 0, psub->to.name);
1033 HeapFree(GetProcessHeap(), 0, psub->from.name);
1034 HeapFree(GetProcessHeap(), 0, psub);
1035 } else {
1036 add_font_subst(&font_subst_list, psub, 0);
1038 /* reset dlen and vlen */
1039 dlen = datalen;
1040 vlen = valuelen;
1042 HeapFree(GetProcessHeap(), 0, data);
1043 HeapFree(GetProcessHeap(), 0, value);
1044 RegCloseKey(hkey);
1049 /*****************************************************************
1050 * get_name_table_entry
1052 * Supply the platform, encoding, language and name ids in req
1053 * and if the name exists the function will fill in the string
1054 * and string_len members. The string is owned by FreeType so
1055 * don't free it. Returns TRUE if the name is found else FALSE.
1057 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1059 FT_SfntName name;
1060 FT_UInt num_names, name_index;
1062 if(FT_IS_SFNT(ft_face))
1064 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1066 for(name_index = 0; name_index < num_names; name_index++)
1068 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1070 if((name.platform_id == req->platform_id) &&
1071 (name.encoding_id == req->encoding_id) &&
1072 (name.language_id == req->language_id) &&
1073 (name.name_id == req->name_id))
1075 req->string = name.string;
1076 req->string_len = name.string_len;
1077 return TRUE;
1082 req->string = NULL;
1083 req->string_len = 0;
1084 return FALSE;
1087 static WCHAR *get_familyname(FT_Face ft_face)
1089 WCHAR *family = NULL;
1090 FT_SfntName name;
1092 name.platform_id = TT_PLATFORM_MICROSOFT;
1093 name.encoding_id = TT_MS_ID_UNICODE_CS;
1094 name.language_id = GetUserDefaultLCID();
1095 name.name_id = TT_NAME_ID_FONT_FAMILY;
1097 if(get_name_table_entry(ft_face, &name))
1099 FT_UInt i;
1101 /* String is not nul terminated and string_len is a byte length. */
1102 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1103 for(i = 0; i < name.string_len / 2; i++)
1105 WORD *tmp = (WORD *)&name.string[i * 2];
1106 family[i] = GET_BE_WORD(*tmp);
1108 family[i] = 0;
1109 TRACE("Got localised name %s\n", debugstr_w(family));
1112 return family;
1116 /*****************************************************************
1117 * load_sfnt_table
1119 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1120 * of FreeType that don't export this function.
1123 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1126 FT_Error err;
1128 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1129 if(pFT_Load_Sfnt_Table)
1131 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1133 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1134 else /* Do it the hard way */
1136 TT_Face tt_face = (TT_Face) ft_face;
1137 SFNT_Interface *sfnt;
1138 if (FT_Version.major==2 && FT_Version.minor==0)
1140 /* 2.0.x */
1141 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1143 else
1145 /* A field was added in the middle of the structure in 2.1.x */
1146 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1148 err = sfnt->load_any(tt_face, table, offset, buf, len);
1150 #else
1151 else
1153 static int msg;
1154 if(!msg)
1156 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1157 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1158 "Please upgrade your freetype library.\n");
1159 msg++;
1161 err = FT_Err_Unimplemented_Feature;
1163 #endif
1164 return err;
1167 static inline int TestStyles(DWORD flags, DWORD styles)
1169 return (flags & styles) == styles;
1172 static int StyleOrdering(Face *face)
1174 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1175 return 3;
1176 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1177 return 2;
1178 if (TestStyles(face->ntmFlags, NTM_BOLD))
1179 return 1;
1180 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1181 return 0;
1183 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1184 debugstr_w(face->family->FamilyName),
1185 debugstr_w(face->StyleName),
1186 face->ntmFlags);
1188 return 9999;
1191 /* Add a style of face to a font family using an ordering of the list such
1192 that regular fonts come before bold and italic, and single styles come
1193 before compound styles. */
1194 static void AddFaceToFamily(Face *face, Family *family)
1196 struct list *entry;
1198 LIST_FOR_EACH( entry, &family->faces )
1200 Face *ent = LIST_ENTRY(entry, Face, entry);
1201 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1203 list_add_before( entry, &face->entry );
1206 #define ADDFONT_EXTERNAL_FONT 0x01
1207 #define ADDFONT_FORCE_BITMAP 0x02
1208 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1210 FT_Face ft_face;
1211 TT_OS2 *pOS2;
1212 TT_Header *pHeader = NULL;
1213 WCHAR *english_family, *localised_family, *StyleW;
1214 DWORD len;
1215 Family *family;
1216 Face *face;
1217 struct list *family_elem_ptr, *face_elem_ptr;
1218 FT_Error err;
1219 FT_Long face_index = 0, num_faces;
1220 #ifdef HAVE_FREETYPE_FTWINFNT_H
1221 FT_WinFNT_HeaderRec winfnt_header;
1222 #endif
1223 int i, bitmap_num, internal_leading;
1224 FONTSIGNATURE fs;
1226 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1227 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1229 #ifdef HAVE_CARBON_CARBON_H
1230 if(file && !fake_family)
1232 char **mac_list = expand_mac_font(file);
1233 if(mac_list)
1235 BOOL had_one = FALSE;
1236 char **cursor;
1237 for(cursor = mac_list; *cursor; cursor++)
1239 had_one = TRUE;
1240 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1241 HeapFree(GetProcessHeap(), 0, *cursor);
1243 HeapFree(GetProcessHeap(), 0, mac_list);
1244 if(had_one)
1245 return 1;
1248 #endif /* HAVE_CARBON_CARBON_H */
1250 do {
1251 char *family_name = fake_family;
1253 if (file)
1255 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1256 err = pFT_New_Face(library, file, face_index, &ft_face);
1257 } else
1259 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1260 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1263 if(err != 0) {
1264 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1265 return 0;
1268 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*/
1269 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1270 pFT_Done_Face(ft_face);
1271 return 0;
1274 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1275 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1276 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1277 pFT_Done_Face(ft_face);
1278 return 0;
1281 if(FT_IS_SFNT(ft_face))
1283 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1284 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1285 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1287 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1288 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1289 pFT_Done_Face(ft_face);
1290 return 0;
1293 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1294 we don't want to load these. */
1295 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1297 FT_ULong len = 0;
1299 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1301 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1302 pFT_Done_Face(ft_face);
1303 return 0;
1308 if(!ft_face->family_name || !ft_face->style_name) {
1309 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1310 pFT_Done_Face(ft_face);
1311 return 0;
1314 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1316 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1317 pFT_Done_Face(ft_face);
1318 return 0;
1321 if (target_family)
1323 localised_family = get_familyname(ft_face);
1324 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1326 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1327 HeapFree(GetProcessHeap(), 0, localised_family);
1328 num_faces = ft_face->num_faces;
1329 pFT_Done_Face(ft_face);
1330 continue;
1332 HeapFree(GetProcessHeap(), 0, localised_family);
1335 if(!family_name)
1336 family_name = ft_face->family_name;
1338 bitmap_num = 0;
1339 do {
1340 My_FT_Bitmap_Size *size = NULL;
1341 FT_ULong tmp_size;
1343 if(!FT_IS_SCALABLE(ft_face))
1344 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1346 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1347 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1348 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1350 localised_family = NULL;
1351 if(!fake_family) {
1352 localised_family = get_familyname(ft_face);
1353 if(localised_family && !strcmpiW(localised_family, english_family)) {
1354 HeapFree(GetProcessHeap(), 0, localised_family);
1355 localised_family = NULL;
1359 family = NULL;
1360 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1361 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1362 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1363 break;
1364 family = NULL;
1366 if(!family) {
1367 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1368 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1369 list_init(&family->faces);
1370 list_add_tail(&font_list, &family->entry);
1372 if(localised_family) {
1373 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1374 subst->from.name = strdupW(english_family);
1375 subst->from.charset = -1;
1376 subst->to.name = strdupW(localised_family);
1377 subst->to.charset = -1;
1378 add_font_subst(&font_subst_list, subst, 0);
1381 HeapFree(GetProcessHeap(), 0, localised_family);
1382 HeapFree(GetProcessHeap(), 0, english_family);
1384 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1385 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1386 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1388 internal_leading = 0;
1389 memset(&fs, 0, sizeof(fs));
1391 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1392 if(pOS2) {
1393 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1394 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1395 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1396 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1397 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1398 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1399 if(pOS2->version == 0) {
1400 FT_UInt dummy;
1402 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1403 fs.fsCsb[0] |= FS_LATIN1;
1404 else
1405 fs.fsCsb[0] |= FS_SYMBOL;
1408 #ifdef HAVE_FREETYPE_FTWINFNT_H
1409 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1410 CHARSETINFO csi;
1411 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1412 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1413 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1414 fs = csi.fs;
1415 internal_leading = winfnt_header.internal_leading;
1417 #endif
1419 face_elem_ptr = list_head(&family->faces);
1420 while(face_elem_ptr) {
1421 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1422 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1423 if(!strcmpiW(face->StyleName, StyleW) &&
1424 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1425 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1426 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1427 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1429 if(fake_family) {
1430 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1431 HeapFree(GetProcessHeap(), 0, StyleW);
1432 pFT_Done_Face(ft_face);
1433 return 1;
1435 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1436 TRACE("Original font is newer so skipping this one\n");
1437 HeapFree(GetProcessHeap(), 0, StyleW);
1438 pFT_Done_Face(ft_face);
1439 return 1;
1440 } else {
1441 TRACE("Replacing original with this one\n");
1442 list_remove(&face->entry);
1443 HeapFree(GetProcessHeap(), 0, face->file);
1444 HeapFree(GetProcessHeap(), 0, face->StyleName);
1445 HeapFree(GetProcessHeap(), 0, face);
1446 break;
1450 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1451 face->cached_enum_data = NULL;
1452 face->StyleName = StyleW;
1453 if (file)
1455 face->file = strdupA(file);
1456 face->font_data_ptr = NULL;
1457 face->font_data_size = 0;
1459 else
1461 face->file = NULL;
1462 face->font_data_ptr = font_data_ptr;
1463 face->font_data_size = font_data_size;
1465 face->face_index = face_index;
1466 face->ntmFlags = 0;
1467 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1468 face->ntmFlags |= NTM_ITALIC;
1469 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1470 face->ntmFlags |= NTM_BOLD;
1471 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1472 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1473 face->family = family;
1474 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1475 face->fs = fs;
1476 memset(&face->fs_links, 0, sizeof(face->fs_links));
1478 if(FT_IS_SCALABLE(ft_face)) {
1479 memset(&face->size, 0, sizeof(face->size));
1480 face->scalable = TRUE;
1481 } else {
1482 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1483 size->height, size->width, size->size >> 6,
1484 size->x_ppem >> 6, size->y_ppem >> 6);
1485 face->size.height = size->height;
1486 face->size.width = size->width;
1487 face->size.size = size->size;
1488 face->size.x_ppem = size->x_ppem;
1489 face->size.y_ppem = size->y_ppem;
1490 face->size.internal_leading = internal_leading;
1491 face->scalable = FALSE;
1494 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1495 tmp_size = 0;
1496 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1498 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1499 face->ntmFlags |= NTM_PS_OPENTYPE;
1502 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1503 face->fs.fsCsb[0], face->fs.fsCsb[1],
1504 face->fs.fsUsb[0], face->fs.fsUsb[1],
1505 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1508 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1509 for(i = 0; i < ft_face->num_charmaps; i++) {
1510 switch(ft_face->charmaps[i]->encoding) {
1511 case FT_ENCODING_UNICODE:
1512 case FT_ENCODING_APPLE_ROMAN:
1513 face->fs.fsCsb[0] |= FS_LATIN1;
1514 break;
1515 case FT_ENCODING_MS_SYMBOL:
1516 face->fs.fsCsb[0] |= FS_SYMBOL;
1517 break;
1518 default:
1519 break;
1524 AddFaceToFamily(face, family);
1526 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1528 num_faces = ft_face->num_faces;
1529 pFT_Done_Face(ft_face);
1530 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1531 debugstr_w(StyleW));
1532 } while(num_faces > ++face_index);
1533 return num_faces;
1536 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1538 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1541 static void DumpFontList(void)
1543 Family *family;
1544 Face *face;
1545 struct list *family_elem_ptr, *face_elem_ptr;
1547 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1548 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1549 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1550 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1551 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1552 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1553 if(!face->scalable)
1554 TRACE(" %d", face->size.height);
1555 TRACE("\n");
1558 return;
1561 /***********************************************************
1562 * The replacement list is a way to map an entire font
1563 * family onto another family. For example adding
1565 * [HKCU\Software\Wine\Fonts\Replacements]
1566 * "Wingdings"="Winedings"
1568 * would enumerate the Winedings font both as Winedings and
1569 * Wingdings. However if a real Wingdings font is present the
1570 * replacement does not take place.
1573 static void LoadReplaceList(void)
1575 HKEY hkey;
1576 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1577 LPWSTR value;
1578 LPVOID data;
1579 Family *family;
1580 Face *face;
1581 struct list *family_elem_ptr, *face_elem_ptr;
1582 CHAR familyA[400];
1584 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1585 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1587 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1588 &valuelen, &datalen, NULL, NULL);
1590 valuelen++; /* returned value doesn't include room for '\0' */
1591 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1592 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1594 dlen = datalen;
1595 vlen = valuelen;
1596 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1597 &dlen) == ERROR_SUCCESS) {
1598 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1599 /* "NewName"="Oldname" */
1600 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1602 /* Find the old family and hence all of the font files
1603 in that family */
1604 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1605 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1606 if(!strcmpiW(family->FamilyName, data)) {
1607 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1608 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1609 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1610 debugstr_w(face->StyleName), familyA);
1611 /* Now add a new entry with the new family name */
1612 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1614 break;
1617 /* reset dlen and vlen */
1618 dlen = datalen;
1619 vlen = valuelen;
1621 HeapFree(GetProcessHeap(), 0, data);
1622 HeapFree(GetProcessHeap(), 0, value);
1623 RegCloseKey(hkey);
1627 /*************************************************************
1628 * init_system_links
1630 static BOOL init_system_links(void)
1632 HKEY hkey;
1633 BOOL ret = FALSE;
1634 DWORD type, max_val, max_data, val_len, data_len, index;
1635 WCHAR *value, *data;
1636 WCHAR *entry, *next;
1637 SYSTEM_LINKS *font_link, *system_font_link;
1638 CHILD_FONT *child_font;
1639 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1640 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1641 FONTSIGNATURE fs;
1642 Family *family;
1643 Face *face;
1644 FontSubst *psub;
1646 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1648 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1649 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1650 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1651 val_len = max_val + 1;
1652 data_len = max_data;
1653 index = 0;
1654 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1656 memset(&fs, 0, sizeof(fs));
1657 psub = get_font_subst(&font_subst_list, value, -1);
1658 /* Don't store fonts that are only substitutes for other fonts */
1659 if(psub)
1661 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1662 goto next;
1664 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1665 font_link->font_name = strdupW(value);
1666 list_init(&font_link->links);
1667 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1669 WCHAR *face_name;
1670 CHILD_FONT *child_font;
1672 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1674 next = entry + strlenW(entry) + 1;
1676 face_name = strchrW(entry, ',');
1677 if(face_name)
1679 *face_name++ = 0;
1680 while(isspaceW(*face_name))
1681 face_name++;
1683 psub = get_font_subst(&font_subst_list, face_name, -1);
1684 if(psub)
1685 face_name = psub->to.name;
1687 face = find_face_from_filename(entry, face_name);
1688 if(!face)
1690 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1691 continue;
1694 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1695 child_font->face = face;
1696 child_font->font = NULL;
1697 fs.fsCsb[0] |= face->fs.fsCsb[0];
1698 fs.fsCsb[1] |= face->fs.fsCsb[1];
1699 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1700 list_add_tail(&font_link->links, &child_font->entry);
1702 family = find_family_from_name(font_link->font_name);
1703 if(family)
1705 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1707 face->fs_links = fs;
1710 list_add_tail(&system_links, &font_link->entry);
1711 next:
1712 val_len = max_val + 1;
1713 data_len = max_data;
1716 HeapFree(GetProcessHeap(), 0, value);
1717 HeapFree(GetProcessHeap(), 0, data);
1718 RegCloseKey(hkey);
1721 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1722 that Tahoma has */
1724 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1725 system_font_link->font_name = strdupW(System);
1726 list_init(&system_font_link->links);
1728 face = find_face_from_filename(tahoma_ttf, Tahoma);
1729 if(face)
1731 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1732 child_font->face = face;
1733 child_font->font = NULL;
1734 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1735 list_add_tail(&system_font_link->links, &child_font->entry);
1737 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1739 if(!strcmpiW(font_link->font_name, Tahoma))
1741 CHILD_FONT *font_link_entry;
1742 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1744 CHILD_FONT *new_child;
1745 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1746 new_child->face = font_link_entry->face;
1747 new_child->font = NULL;
1748 list_add_tail(&system_font_link->links, &new_child->entry);
1750 break;
1753 list_add_tail(&system_links, &system_font_link->entry);
1754 return ret;
1757 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1759 DIR *dir;
1760 struct dirent *dent;
1761 char path[MAX_PATH];
1763 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1765 dir = opendir(dirname);
1766 if(!dir) {
1767 WARN("Can't open directory %s\n", debugstr_a(dirname));
1768 return FALSE;
1770 while((dent = readdir(dir)) != NULL) {
1771 struct stat statbuf;
1773 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1774 continue;
1776 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1778 sprintf(path, "%s/%s", dirname, dent->d_name);
1780 if(stat(path, &statbuf) == -1)
1782 WARN("Can't stat %s\n", debugstr_a(path));
1783 continue;
1785 if(S_ISDIR(statbuf.st_mode))
1786 ReadFontDir(path, external_fonts);
1787 else
1788 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1790 closedir(dir);
1791 return TRUE;
1794 static void load_fontconfig_fonts(void)
1796 #ifdef SONAME_LIBFONTCONFIG
1797 void *fc_handle = NULL;
1798 FcConfig *config;
1799 FcPattern *pat;
1800 FcObjectSet *os;
1801 FcFontSet *fontset;
1802 int i, len;
1803 char *file;
1804 const char *ext;
1806 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1807 if(!fc_handle) {
1808 TRACE("Wine cannot find the fontconfig library (%s).\n",
1809 SONAME_LIBFONTCONFIG);
1810 return;
1812 #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;}
1813 LOAD_FUNCPTR(FcConfigGetCurrent);
1814 LOAD_FUNCPTR(FcFontList);
1815 LOAD_FUNCPTR(FcFontSetDestroy);
1816 LOAD_FUNCPTR(FcInit);
1817 LOAD_FUNCPTR(FcObjectSetAdd);
1818 LOAD_FUNCPTR(FcObjectSetCreate);
1819 LOAD_FUNCPTR(FcObjectSetDestroy);
1820 LOAD_FUNCPTR(FcPatternCreate);
1821 LOAD_FUNCPTR(FcPatternDestroy);
1822 LOAD_FUNCPTR(FcPatternGetBool);
1823 LOAD_FUNCPTR(FcPatternGetString);
1824 #undef LOAD_FUNCPTR
1826 if(!pFcInit()) return;
1828 config = pFcConfigGetCurrent();
1829 pat = pFcPatternCreate();
1830 os = pFcObjectSetCreate();
1831 pFcObjectSetAdd(os, FC_FILE);
1832 pFcObjectSetAdd(os, FC_SCALABLE);
1833 fontset = pFcFontList(config, pat, os);
1834 if(!fontset) return;
1835 for(i = 0; i < fontset->nfont; i++) {
1836 FcBool scalable;
1838 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1839 continue;
1840 TRACE("fontconfig: %s\n", file);
1842 /* We're just interested in OT/TT fonts for now, so this hack just
1843 picks up the scalable fonts without extensions .pf[ab] to save time
1844 loading every other font */
1846 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1848 TRACE("not scalable\n");
1849 continue;
1852 len = strlen( file );
1853 if(len < 4) continue;
1854 ext = &file[ len - 3 ];
1855 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1856 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1858 pFcFontSetDestroy(fontset);
1859 pFcObjectSetDestroy(os);
1860 pFcPatternDestroy(pat);
1861 sym_not_found:
1862 #endif
1863 return;
1866 static BOOL load_font_from_data_dir(LPCWSTR file)
1868 BOOL ret = FALSE;
1869 const char *data_dir = wine_get_data_dir();
1871 if (!data_dir) data_dir = wine_get_build_dir();
1873 if (data_dir)
1875 INT len;
1876 char *unix_name;
1878 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1880 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1882 strcpy(unix_name, data_dir);
1883 strcat(unix_name, "/fonts/");
1885 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1887 EnterCriticalSection( &freetype_cs );
1888 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1889 LeaveCriticalSection( &freetype_cs );
1890 HeapFree(GetProcessHeap(), 0, unix_name);
1892 return ret;
1895 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1897 static const WCHAR slashW[] = {'\\','\0'};
1898 BOOL ret = FALSE;
1899 WCHAR windowsdir[MAX_PATH];
1900 char *unixname;
1902 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1903 strcatW(windowsdir, fontsW);
1904 strcatW(windowsdir, slashW);
1905 strcatW(windowsdir, file);
1906 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1907 EnterCriticalSection( &freetype_cs );
1908 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1909 LeaveCriticalSection( &freetype_cs );
1910 HeapFree(GetProcessHeap(), 0, unixname);
1912 return ret;
1915 static void load_system_fonts(void)
1917 HKEY hkey;
1918 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1919 const WCHAR * const *value;
1920 DWORD dlen, type;
1921 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1922 char *unixname;
1924 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1925 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1926 strcatW(windowsdir, fontsW);
1927 for(value = SystemFontValues; *value; value++) {
1928 dlen = sizeof(data);
1929 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1930 type == REG_SZ) {
1931 BOOL added = FALSE;
1933 sprintfW(pathW, fmtW, windowsdir, data);
1934 if((unixname = wine_get_unix_file_name(pathW))) {
1935 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1936 HeapFree(GetProcessHeap(), 0, unixname);
1938 if (!added)
1939 load_font_from_data_dir(data);
1942 RegCloseKey(hkey);
1946 /*************************************************************
1948 * This adds registry entries for any externally loaded fonts
1949 * (fonts from fontconfig or FontDirs). It also deletes entries
1950 * of no longer existing fonts.
1953 static void update_reg_entries(void)
1955 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1956 LPWSTR valueW;
1957 DWORD len, len_fam;
1958 Family *family;
1959 Face *face;
1960 struct list *family_elem_ptr, *face_elem_ptr;
1961 WCHAR *file;
1962 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1963 static const WCHAR spaceW[] = {' ', '\0'};
1964 char *path;
1966 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1967 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1968 ERR("Can't create Windows font reg key\n");
1969 goto end;
1972 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1973 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1974 ERR("Can't create Windows font reg key\n");
1975 goto end;
1978 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1979 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1980 ERR("Can't create external font reg key\n");
1981 goto end;
1984 /* enumerate the fonts and add external ones to the two keys */
1986 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1987 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1988 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1989 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1990 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1991 if(!face->external) continue;
1992 len = len_fam;
1993 if (!(face->ntmFlags & NTM_REGULAR))
1994 len = len_fam + strlenW(face->StyleName) + 1;
1995 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1996 strcpyW(valueW, family->FamilyName);
1997 if(len != len_fam) {
1998 strcatW(valueW, spaceW);
1999 strcatW(valueW, face->StyleName);
2001 strcatW(valueW, TrueType);
2003 file = wine_get_dos_file_name(face->file);
2004 if(file)
2005 len = strlenW(file) + 1;
2006 else
2008 if((path = strrchr(face->file, '/')) == NULL)
2009 path = face->file;
2010 else
2011 path++;
2012 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2014 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2015 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2017 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2018 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2019 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2021 HeapFree(GetProcessHeap(), 0, file);
2022 HeapFree(GetProcessHeap(), 0, valueW);
2025 end:
2026 if(external_key) RegCloseKey(external_key);
2027 if(win9x_key) RegCloseKey(win9x_key);
2028 if(winnt_key) RegCloseKey(winnt_key);
2029 return;
2032 static void delete_external_font_keys(void)
2034 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2035 DWORD dlen, vlen, datalen, valuelen, i, type;
2036 LPWSTR valueW;
2037 LPVOID data;
2039 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2040 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2041 ERR("Can't create Windows font reg key\n");
2042 goto end;
2045 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2046 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2047 ERR("Can't create Windows font reg key\n");
2048 goto end;
2051 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2052 ERR("Can't create external font reg key\n");
2053 goto end;
2056 /* Delete all external fonts added last time */
2058 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2059 &valuelen, &datalen, NULL, NULL);
2060 valuelen++; /* returned value doesn't include room for '\0' */
2061 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2062 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2064 dlen = datalen * sizeof(WCHAR);
2065 vlen = valuelen;
2066 i = 0;
2067 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2068 &dlen) == ERROR_SUCCESS) {
2070 RegDeleteValueW(winnt_key, valueW);
2071 RegDeleteValueW(win9x_key, valueW);
2072 /* reset dlen and vlen */
2073 dlen = datalen;
2074 vlen = valuelen;
2076 HeapFree(GetProcessHeap(), 0, data);
2077 HeapFree(GetProcessHeap(), 0, valueW);
2079 /* Delete the old external fonts key */
2080 RegCloseKey(external_key);
2081 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2083 end:
2084 if(win9x_key) RegCloseKey(win9x_key);
2085 if(winnt_key) RegCloseKey(winnt_key);
2088 /*************************************************************
2089 * WineEngAddFontResourceEx
2092 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2094 INT ret = 0;
2096 GDI_CheckNotLock();
2098 if (ft_handle) /* do it only if we have freetype up and running */
2100 char *unixname;
2102 if(flags)
2103 FIXME("Ignoring flags %x\n", flags);
2105 if((unixname = wine_get_unix_file_name(file)))
2107 EnterCriticalSection( &freetype_cs );
2108 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2109 LeaveCriticalSection( &freetype_cs );
2110 HeapFree(GetProcessHeap(), 0, unixname);
2112 if (!ret && !strchrW(file, '\\')) {
2113 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2114 ret = load_font_from_winfonts_dir(file);
2115 if (!ret) {
2116 /* Try in datadir/fonts (or builddir/fonts),
2117 * needed for Magic the Gathering Online
2119 ret = load_font_from_data_dir(file);
2123 return ret;
2126 /*************************************************************
2127 * WineEngAddFontMemResourceEx
2130 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2132 GDI_CheckNotLock();
2134 if (ft_handle) /* do it only if we have freetype up and running */
2136 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2138 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2139 memcpy(pFontCopy, pbFont, cbFont);
2141 EnterCriticalSection( &freetype_cs );
2142 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2143 LeaveCriticalSection( &freetype_cs );
2145 if (*pcFonts == 0)
2147 TRACE("AddFontToList failed\n");
2148 HeapFree(GetProcessHeap(), 0, pFontCopy);
2149 return 0;
2151 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2152 * For now return something unique but quite random
2154 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2155 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2158 *pcFonts = 0;
2159 return 0;
2162 /*************************************************************
2163 * WineEngRemoveFontResourceEx
2166 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2168 GDI_CheckNotLock();
2169 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2170 return TRUE;
2173 static const struct nls_update_font_list
2175 UINT ansi_cp, oem_cp;
2176 const char *oem, *fixed, *system;
2177 const char *courier, *serif, *small, *sserif;
2178 /* these are for font substitutes */
2179 const char *shelldlg, *tmsrmn;
2180 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2181 *helv_0, *tmsrmn_0;
2182 const struct subst
2184 const char *from, *to;
2185 } arial_0, courier_new_0, times_new_roman_0;
2186 } nls_update_font_list[] =
2188 /* Latin 1 (United States) */
2189 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2190 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2191 "Tahoma","Times New Roman",
2192 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2193 { 0 }, { 0 }, { 0 }
2195 /* Latin 1 (Multilingual) */
2196 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2197 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2198 "Tahoma","Times New Roman", /* FIXME unverified */
2199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2200 { 0 }, { 0 }, { 0 }
2202 /* Eastern Europe */
2203 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2204 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,238", "System,238",
2207 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2208 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2209 { "Arial CE,0", "Arial,238" },
2210 { "Courier New CE,0", "Courier New,238" },
2211 { "Times New Roman CE,0", "Times New Roman,238" }
2213 /* Cyrillic */
2214 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2215 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,204", "System,204",
2218 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2219 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2220 { "Arial Cyr,0", "Arial,204" },
2221 { "Courier New Cyr,0", "Courier New,204" },
2222 { "Times New Roman Cyr,0", "Times New Roman,204" }
2224 /* Greek */
2225 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2226 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,161", "System,161",
2229 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2230 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2231 { "Arial Greek,0", "Arial,161" },
2232 { "Courier New Greek,0", "Courier New,161" },
2233 { "Times New Roman Greek,0", "Times New Roman,161" }
2235 /* Turkish */
2236 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2237 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,162", "System,162",
2240 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2241 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2242 { "Arial Tur,0", "Arial,162" },
2243 { "Courier New Tur,0", "Courier New,162" },
2244 { "Times New Roman Tur,0", "Times New Roman,162" }
2246 /* Hebrew */
2247 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2248 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2249 "Tahoma","Times New Roman", /* FIXME unverified */
2250 "Fixedsys,177", "System,177",
2251 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2252 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2253 { 0 }, { 0 }, { 0 }
2255 /* Arabic */
2256 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2257 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2258 "Tahoma","Times New Roman", /* FIXME unverified */
2259 "Fixedsys,178", "System,178",
2260 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2261 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2262 { 0 }, { 0 }, { 0 }
2264 /* Baltic */
2265 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2266 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2267 "Tahoma","Times New Roman", /* FIXME unverified */
2268 "Fixedsys,186", "System,186",
2269 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2270 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2271 { "Arial Baltic,0", "Arial,186" },
2272 { "Courier New Baltic,0", "Courier New,186" },
2273 { "Times New Roman Baltic,0", "Times New Roman,186" }
2275 /* Vietnamese */
2276 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2277 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2280 { 0 }, { 0 }, { 0 }
2282 /* Thai */
2283 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2284 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2285 "Tahoma","Times New Roman", /* FIXME unverified */
2286 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2287 { 0 }, { 0 }, { 0 }
2289 /* Japanese */
2290 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2291 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2292 "MS UI Gothic","MS Serif",
2293 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2294 { 0 }, { 0 }, { 0 }
2296 /* Chinese Simplified */
2297 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2299 "SimSun", "NSimSun",
2300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2301 { 0 }, { 0 }, { 0 }
2303 /* Korean */
2304 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2306 "Gulim", "Batang",
2307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2308 { 0 }, { 0 }, { 0 }
2310 /* Chinese Traditional */
2311 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2312 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2313 "PMingLiU", "MingLiU",
2314 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2315 { 0 }, { 0 }, { 0 }
2319 static const WCHAR *font_links_list[] =
2321 Lucida_Sans_Unicode,
2322 Microsoft_Sans_Serif,
2323 Tahoma
2326 static const struct font_links_defaults_list
2328 /* Keyed off substitution for "MS Shell Dlg" */
2329 const WCHAR *shelldlg;
2330 /* Maximum of four substitutes, plus terminating NULL pointer */
2331 const WCHAR *substitutes[5];
2332 } font_links_defaults_list[] =
2334 /* Non East-Asian */
2335 { Tahoma, /* FIXME unverified ordering */
2336 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2338 /* Below lists are courtesy of
2339 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2341 /* Japanese */
2342 { MS_UI_Gothic,
2343 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2345 /* Chinese Simplified */
2346 { SimSun,
2347 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2349 /* Korean */
2350 { Gulim,
2351 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2353 /* Chinese Traditional */
2354 { PMingLiU,
2355 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2359 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2361 return ( ansi_cp == 932 /* CP932 for Japanese */
2362 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2363 || ansi_cp == 949 /* CP949 for Korean */
2364 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2367 static inline HKEY create_fonts_NT_registry_key(void)
2369 HKEY hkey = 0;
2371 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2372 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2373 return hkey;
2376 static inline HKEY create_fonts_9x_registry_key(void)
2378 HKEY hkey = 0;
2380 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2381 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2382 return hkey;
2385 static inline HKEY create_config_fonts_registry_key(void)
2387 HKEY hkey = 0;
2389 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2390 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2391 return hkey;
2394 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2396 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2397 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2398 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2399 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2402 static void set_value_key(HKEY hkey, const char *name, const char *value)
2404 if (value)
2405 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2406 else if (name)
2407 RegDeleteValueA(hkey, name);
2410 static void update_font_info(void)
2412 char buf[40], cpbuf[40];
2413 DWORD len, type;
2414 HKEY hkey = 0;
2415 UINT i, ansi_cp = 0, oem_cp = 0;
2416 BOOL done = FALSE;
2418 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2419 return;
2421 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2422 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2423 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2424 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2425 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2427 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2428 if (is_dbcs_ansi_cp(ansi_cp))
2429 use_default_fallback = TRUE;
2431 len = sizeof(buf);
2432 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2434 if (!strcmp( buf, cpbuf )) /* already set correctly */
2436 RegCloseKey(hkey);
2437 return;
2439 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2441 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2443 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2444 RegCloseKey(hkey);
2446 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2448 HKEY hkey;
2450 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2451 nls_update_font_list[i].oem_cp == oem_cp)
2453 hkey = create_config_fonts_registry_key();
2454 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2455 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2456 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2457 RegCloseKey(hkey);
2459 hkey = create_fonts_NT_registry_key();
2460 add_font_list(hkey, &nls_update_font_list[i]);
2461 RegCloseKey(hkey);
2463 hkey = create_fonts_9x_registry_key();
2464 add_font_list(hkey, &nls_update_font_list[i]);
2465 RegCloseKey(hkey);
2467 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2469 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2470 strlen(nls_update_font_list[i].shelldlg)+1);
2471 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2472 strlen(nls_update_font_list[i].tmsrmn)+1);
2474 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2475 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2476 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2477 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2478 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2479 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2480 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2481 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2483 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2484 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2485 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2487 RegCloseKey(hkey);
2489 done = TRUE;
2491 else
2493 /* Delete the FontSubstitutes from other locales */
2494 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2496 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2497 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2498 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2499 RegCloseKey(hkey);
2503 if (!done)
2504 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2506 /* Clear out system links */
2507 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2510 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2512 const WCHAR *value;
2513 int i;
2514 FontSubst *psub;
2515 Family *family;
2516 Face *face;
2517 const char *file;
2518 WCHAR *fileW;
2519 int fileLen;
2520 WCHAR buff[MAX_PATH];
2521 WCHAR *data;
2522 int entryLen;
2524 static const WCHAR comma[] = {',',0};
2526 RegDeleteValueW(hkey, name);
2527 if (values)
2529 data = buff;
2530 data[0] = '\0';
2531 for (i = 0; values[i] != NULL; i++)
2533 value = values[i];
2534 if (!strcmpiW(name,value))
2535 continue;
2536 psub = get_font_subst(&font_subst_list, value, -1);
2537 if(psub)
2538 value = psub->to.name;
2539 family = find_family_from_name(value);
2540 if (!family)
2541 continue;
2542 file = NULL;
2543 /* Use first extant filename for this Family */
2544 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2546 if (!face->file)
2547 continue;
2548 file = strrchr(face->file, '/');
2549 if (!file)
2550 file = face->file;
2551 else
2552 file++;
2553 break;
2555 if (!file)
2556 continue;
2557 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2558 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2559 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2560 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2561 if (sizeof(buff)-(data-buff) < entryLen + 1)
2563 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2564 HeapFree(GetProcessHeap(), 0, fileW);
2565 break;
2567 strcpyW(data, fileW);
2568 strcatW(data, comma);
2569 strcatW(data, value);
2570 data += entryLen;
2571 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2572 HeapFree(GetProcessHeap(), 0, fileW);
2574 if (data != buff)
2576 *data='\0';
2577 data++;
2578 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2579 } else
2580 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2581 } else
2582 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2585 static void update_system_links(void)
2587 HKEY hkey = 0;
2588 UINT i, j;
2589 BOOL done = FALSE;
2590 DWORD disposition;
2591 FontSubst *psub;
2593 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2595 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2597 if (disposition == REG_OPENED_EXISTING_KEY)
2599 TRACE("SystemLink key already exists, doing nothing\n");
2600 RegCloseKey(hkey);
2601 return;
2604 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2605 if (!psub) {
2606 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2607 RegCloseKey(hkey);
2608 return;
2611 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2613 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2615 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2616 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2618 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2619 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2620 done = TRUE;
2622 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2624 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2627 RegCloseKey(hkey);
2628 if (!done)
2629 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2630 } else
2631 WARN("failed to create SystemLink key\n");
2635 static BOOL init_freetype(void)
2637 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2638 if(!ft_handle) {
2639 WINE_MESSAGE(
2640 "Wine cannot find the FreeType font library. To enable Wine to\n"
2641 "use TrueType fonts please install a version of FreeType greater than\n"
2642 "or equal to 2.0.5.\n"
2643 "http://www.freetype.org\n");
2644 return FALSE;
2647 #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;}
2649 LOAD_FUNCPTR(FT_Vector_Unit)
2650 LOAD_FUNCPTR(FT_Done_Face)
2651 LOAD_FUNCPTR(FT_Get_Char_Index)
2652 LOAD_FUNCPTR(FT_Get_Module)
2653 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2654 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2655 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2656 LOAD_FUNCPTR(FT_Init_FreeType)
2657 LOAD_FUNCPTR(FT_Load_Glyph)
2658 LOAD_FUNCPTR(FT_Matrix_Multiply)
2659 #ifndef FT_MULFIX_INLINED
2660 LOAD_FUNCPTR(FT_MulFix)
2661 #endif
2662 LOAD_FUNCPTR(FT_New_Face)
2663 LOAD_FUNCPTR(FT_New_Memory_Face)
2664 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2665 LOAD_FUNCPTR(FT_Outline_Transform)
2666 LOAD_FUNCPTR(FT_Outline_Translate)
2667 LOAD_FUNCPTR(FT_Select_Charmap)
2668 LOAD_FUNCPTR(FT_Set_Charmap)
2669 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2670 LOAD_FUNCPTR(FT_Vector_Transform)
2671 LOAD_FUNCPTR(FT_Render_Glyph)
2673 #undef LOAD_FUNCPTR
2674 /* Don't warn if these ones are missing */
2675 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2676 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2677 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2678 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2679 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2680 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2681 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2682 #endif
2683 #ifdef HAVE_FREETYPE_FTWINFNT_H
2684 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2685 #endif
2686 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2687 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2688 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2689 <= 2.0.3 has FT_Sqrt64 */
2690 goto sym_not_found;
2693 if(pFT_Init_FreeType(&library) != 0) {
2694 ERR("Can't init FreeType library\n");
2695 wine_dlclose(ft_handle, NULL, 0);
2696 ft_handle = NULL;
2697 return FALSE;
2699 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2700 if (pFT_Library_Version)
2701 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2703 if (FT_Version.major<=0)
2705 FT_Version.major=2;
2706 FT_Version.minor=0;
2707 FT_Version.patch=5;
2709 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2710 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2711 ((FT_Version.minor << 8) & 0x00ff00) |
2712 ((FT_Version.patch ) & 0x0000ff);
2714 return TRUE;
2716 sym_not_found:
2717 WINE_MESSAGE(
2718 "Wine cannot find certain functions that it needs inside the FreeType\n"
2719 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2720 "FreeType to at least version 2.0.5.\n"
2721 "http://www.freetype.org\n");
2722 wine_dlclose(ft_handle, NULL, 0);
2723 ft_handle = NULL;
2724 return FALSE;
2727 /*************************************************************
2728 * WineEngInit
2730 * Initialize FreeType library and create a list of available faces
2732 BOOL WineEngInit(void)
2734 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2735 static const WCHAR pathW[] = {'P','a','t','h',0};
2736 HKEY hkey;
2737 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2738 WCHAR windowsdir[MAX_PATH];
2739 char *unixname;
2740 HANDLE font_mutex;
2741 const char *data_dir;
2743 TRACE("\n");
2745 /* update locale dependent font info in registry */
2746 update_font_info();
2748 if(!init_freetype()) return FALSE;
2750 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2751 ERR("Failed to create font mutex\n");
2752 return FALSE;
2754 WaitForSingleObject(font_mutex, INFINITE);
2756 delete_external_font_keys();
2758 /* load the system bitmap fonts */
2759 load_system_fonts();
2761 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2762 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2763 strcatW(windowsdir, fontsW);
2764 if((unixname = wine_get_unix_file_name(windowsdir)))
2766 ReadFontDir(unixname, FALSE);
2767 HeapFree(GetProcessHeap(), 0, unixname);
2770 /* load the system truetype fonts */
2771 data_dir = wine_get_data_dir();
2772 if (!data_dir) data_dir = wine_get_build_dir();
2773 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2774 strcpy(unixname, data_dir);
2775 strcat(unixname, "/fonts/");
2776 ReadFontDir(unixname, TRUE);
2777 HeapFree(GetProcessHeap(), 0, unixname);
2780 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2781 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2782 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2783 will skip these. */
2784 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2785 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2786 &hkey) == ERROR_SUCCESS) {
2787 LPWSTR data, valueW;
2788 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2789 &valuelen, &datalen, NULL, NULL);
2791 valuelen++; /* returned value doesn't include room for '\0' */
2792 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2793 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2794 if (valueW && data)
2796 dlen = datalen * sizeof(WCHAR);
2797 vlen = valuelen;
2798 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2799 &dlen) == ERROR_SUCCESS) {
2800 if(data[0] && (data[1] == ':'))
2802 if((unixname = wine_get_unix_file_name(data)))
2804 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2805 HeapFree(GetProcessHeap(), 0, unixname);
2808 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2810 WCHAR pathW[MAX_PATH];
2811 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2812 BOOL added = FALSE;
2814 sprintfW(pathW, fmtW, windowsdir, data);
2815 if((unixname = wine_get_unix_file_name(pathW)))
2817 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2818 HeapFree(GetProcessHeap(), 0, unixname);
2820 if (!added)
2821 load_font_from_data_dir(data);
2823 /* reset dlen and vlen */
2824 dlen = datalen;
2825 vlen = valuelen;
2828 HeapFree(GetProcessHeap(), 0, data);
2829 HeapFree(GetProcessHeap(), 0, valueW);
2830 RegCloseKey(hkey);
2833 load_fontconfig_fonts();
2835 /* then look in any directories that we've specified in the config file */
2836 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2837 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2839 DWORD len;
2840 LPWSTR valueW;
2841 LPSTR valueA, ptr;
2843 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2845 len += sizeof(WCHAR);
2846 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2847 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2849 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2850 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2851 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2852 TRACE( "got font path %s\n", debugstr_a(valueA) );
2853 ptr = valueA;
2854 while (ptr)
2856 LPSTR next = strchr( ptr, ':' );
2857 if (next) *next++ = 0;
2858 ReadFontDir( ptr, TRUE );
2859 ptr = next;
2861 HeapFree( GetProcessHeap(), 0, valueA );
2863 HeapFree( GetProcessHeap(), 0, valueW );
2865 RegCloseKey(hkey);
2868 DumpFontList();
2869 LoadSubstList();
2870 DumpSubstList();
2871 LoadReplaceList();
2872 update_reg_entries();
2874 update_system_links();
2875 init_system_links();
2877 ReleaseMutex(font_mutex);
2878 return TRUE;
2882 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2884 TT_OS2 *pOS2;
2885 TT_HoriHeader *pHori;
2887 LONG ppem;
2889 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2890 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2892 if(height == 0) height = 16;
2894 /* Calc. height of EM square:
2896 * For +ve lfHeight we have
2897 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2898 * Re-arranging gives:
2899 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2901 * For -ve lfHeight we have
2902 * |lfHeight| = ppem
2903 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2904 * with il = winAscent + winDescent - units_per_em]
2908 if(height > 0) {
2909 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2910 ppem = MulDiv(ft_face->units_per_EM, height,
2911 pHori->Ascender - pHori->Descender);
2912 else
2913 ppem = MulDiv(ft_face->units_per_EM, height,
2914 pOS2->usWinAscent + pOS2->usWinDescent);
2916 else
2917 ppem = -height;
2919 return ppem;
2922 static struct font_mapping *map_font_file( const char *name )
2924 struct font_mapping *mapping;
2925 struct stat st;
2926 int fd;
2928 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2929 if (fstat( fd, &st ) == -1) goto error;
2931 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2933 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2935 mapping->refcount++;
2936 close( fd );
2937 return mapping;
2940 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2941 goto error;
2943 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2944 close( fd );
2946 if (mapping->data == MAP_FAILED)
2948 HeapFree( GetProcessHeap(), 0, mapping );
2949 return NULL;
2951 mapping->refcount = 1;
2952 mapping->dev = st.st_dev;
2953 mapping->ino = st.st_ino;
2954 mapping->size = st.st_size;
2955 list_add_tail( &mappings_list, &mapping->entry );
2956 return mapping;
2958 error:
2959 close( fd );
2960 return NULL;
2963 static void unmap_font_file( struct font_mapping *mapping )
2965 if (!--mapping->refcount)
2967 list_remove( &mapping->entry );
2968 munmap( mapping->data, mapping->size );
2969 HeapFree( GetProcessHeap(), 0, mapping );
2973 static LONG load_VDMX(GdiFont*, LONG);
2975 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2977 FT_Error err;
2978 FT_Face ft_face;
2979 void *data_ptr;
2980 DWORD data_size;
2982 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2984 if (face->file)
2986 if (!(font->mapping = map_font_file( face->file )))
2988 WARN("failed to map %s\n", debugstr_a(face->file));
2989 return 0;
2991 data_ptr = font->mapping->data;
2992 data_size = font->mapping->size;
2994 else
2996 data_ptr = face->font_data_ptr;
2997 data_size = face->font_data_size;
3000 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3001 if(err) {
3002 ERR("FT_New_Face rets %d\n", err);
3003 return 0;
3006 /* set it here, as load_VDMX needs it */
3007 font->ft_face = ft_face;
3009 if(FT_IS_SCALABLE(ft_face)) {
3010 /* load the VDMX table if we have one */
3011 font->ppem = load_VDMX(font, height);
3012 if(font->ppem == 0)
3013 font->ppem = calc_ppem_for_height(ft_face, height);
3014 TRACE("height %d => ppem %d\n", height, font->ppem);
3016 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3017 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3018 } else {
3019 font->ppem = height;
3020 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3021 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3023 return ft_face;
3027 static int get_nearest_charset(Face *face, int *cp)
3029 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3030 a single face with the requested charset. The idea is to check if
3031 the selected font supports the current ANSI codepage, if it does
3032 return the corresponding charset, else return the first charset */
3034 CHARSETINFO csi;
3035 int acp = GetACP(), i;
3036 DWORD fs0;
3038 *cp = acp;
3039 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3040 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3041 return csi.ciCharset;
3043 for(i = 0; i < 32; i++) {
3044 fs0 = 1L << i;
3045 if(face->fs.fsCsb[0] & fs0) {
3046 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3047 *cp = csi.ciACP;
3048 return csi.ciCharset;
3050 else
3051 FIXME("TCI failing on %x\n", fs0);
3055 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3056 face->fs.fsCsb[0], face->file);
3057 *cp = acp;
3058 return DEFAULT_CHARSET;
3061 static GdiFont *alloc_font(void)
3063 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3064 ret->gmsize = 1;
3065 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3066 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3067 ret->potm = NULL;
3068 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3069 ret->total_kern_pairs = (DWORD)-1;
3070 ret->kern_pairs = NULL;
3071 list_init(&ret->hfontlist);
3072 list_init(&ret->child_fonts);
3073 return ret;
3076 static void free_font(GdiFont *font)
3078 struct list *cursor, *cursor2;
3079 DWORD i;
3081 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3083 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3084 list_remove(cursor);
3085 if(child->font)
3086 free_font(child->font);
3087 HeapFree(GetProcessHeap(), 0, child);
3090 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3092 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3093 DeleteObject(hfontlist->hfont);
3094 list_remove(&hfontlist->entry);
3095 HeapFree(GetProcessHeap(), 0, hfontlist);
3098 if (font->ft_face) pFT_Done_Face(font->ft_face);
3099 if (font->mapping) unmap_font_file( font->mapping );
3100 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3101 HeapFree(GetProcessHeap(), 0, font->potm);
3102 HeapFree(GetProcessHeap(), 0, font->name);
3103 for (i = 0; i < font->gmsize; i++)
3104 HeapFree(GetProcessHeap(),0,font->gm[i]);
3105 HeapFree(GetProcessHeap(), 0, font->gm);
3106 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3107 HeapFree(GetProcessHeap(), 0, font);
3111 /*************************************************************
3112 * load_VDMX
3114 * load the vdmx entry for the specified height
3117 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3118 ( ( (FT_ULong)_x4 << 24 ) | \
3119 ( (FT_ULong)_x3 << 16 ) | \
3120 ( (FT_ULong)_x2 << 8 ) | \
3121 (FT_ULong)_x1 )
3123 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3125 typedef struct {
3126 BYTE bCharSet;
3127 BYTE xRatio;
3128 BYTE yStartRatio;
3129 BYTE yEndRatio;
3130 } Ratios;
3132 typedef struct {
3133 WORD recs;
3134 BYTE startsz;
3135 BYTE endsz;
3136 } VDMX_group;
3138 static LONG load_VDMX(GdiFont *font, LONG height)
3140 WORD hdr[3], tmp;
3141 VDMX_group group;
3142 BYTE devXRatio, devYRatio;
3143 USHORT numRecs, numRatios;
3144 DWORD result, offset = -1;
3145 LONG ppem = 0;
3146 int i;
3148 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3150 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3151 return ppem;
3153 /* FIXME: need the real device aspect ratio */
3154 devXRatio = 1;
3155 devYRatio = 1;
3157 numRecs = GET_BE_WORD(hdr[1]);
3158 numRatios = GET_BE_WORD(hdr[2]);
3160 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3161 for(i = 0; i < numRatios; i++) {
3162 Ratios ratio;
3164 offset = (3 * 2) + (i * sizeof(Ratios));
3165 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3166 offset = -1;
3168 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3170 if((ratio.xRatio == 0 &&
3171 ratio.yStartRatio == 0 &&
3172 ratio.yEndRatio == 0) ||
3173 (devXRatio == ratio.xRatio &&
3174 devYRatio >= ratio.yStartRatio &&
3175 devYRatio <= ratio.yEndRatio))
3177 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3178 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3179 offset = GET_BE_WORD(tmp);
3180 break;
3184 if(offset == -1) {
3185 FIXME("No suitable ratio found\n");
3186 return ppem;
3189 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3190 USHORT recs;
3191 BYTE startsz, endsz;
3192 WORD *vTable;
3194 recs = GET_BE_WORD(group.recs);
3195 startsz = group.startsz;
3196 endsz = group.endsz;
3198 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3200 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3201 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3202 if(result == GDI_ERROR) {
3203 FIXME("Failed to retrieve vTable\n");
3204 goto end;
3207 if(height > 0) {
3208 for(i = 0; i < recs; i++) {
3209 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3210 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3211 ppem = GET_BE_WORD(vTable[i * 3]);
3213 if(yMax + -yMin == height) {
3214 font->yMax = yMax;
3215 font->yMin = yMin;
3216 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3217 break;
3219 if(yMax + -yMin > height) {
3220 if(--i < 0) {
3221 ppem = 0;
3222 goto end; /* failed */
3224 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3225 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3226 ppem = GET_BE_WORD(vTable[i * 3]);
3227 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3228 break;
3231 if(!font->yMax) {
3232 ppem = 0;
3233 TRACE("ppem not found for height %d\n", height);
3236 end:
3237 HeapFree(GetProcessHeap(), 0, vTable);
3240 return ppem;
3243 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3245 if(font->font_desc.hash != fd->hash) return TRUE;
3246 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3247 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3248 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3249 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3252 static void calc_hash(FONT_DESC *pfd)
3254 DWORD hash = 0, *ptr, two_chars;
3255 WORD *pwc;
3256 unsigned int i;
3258 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3259 hash ^= *ptr;
3260 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3261 hash ^= *ptr;
3262 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3263 two_chars = *ptr;
3264 pwc = (WCHAR *)&two_chars;
3265 if(!*pwc) break;
3266 *pwc = toupperW(*pwc);
3267 pwc++;
3268 *pwc = toupperW(*pwc);
3269 hash ^= two_chars;
3270 if(!*pwc) break;
3272 hash ^= !pfd->can_use_bitmap;
3273 pfd->hash = hash;
3274 return;
3277 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3279 GdiFont *ret;
3280 FONT_DESC fd;
3281 HFONTLIST *hflist;
3282 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3284 fd.lf = *plf;
3285 fd.matrix = *pmat;
3286 fd.can_use_bitmap = can_use_bitmap;
3287 calc_hash(&fd);
3289 /* try the child list */
3290 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3291 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3292 if(!fontcmp(ret, &fd)) {
3293 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3294 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3295 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3296 if(hflist->hfont == hfont)
3297 return ret;
3302 /* try the in-use list */
3303 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3304 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3305 if(!fontcmp(ret, &fd)) {
3306 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3307 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3308 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3309 if(hflist->hfont == hfont)
3310 return ret;
3312 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3313 hflist->hfont = hfont;
3314 list_add_head(&ret->hfontlist, &hflist->entry);
3315 return ret;
3319 /* then the unused list */
3320 font_elem_ptr = list_head(&unused_gdi_font_list);
3321 while(font_elem_ptr) {
3322 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3323 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3324 if(!fontcmp(ret, &fd)) {
3325 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3326 assert(list_empty(&ret->hfontlist));
3327 TRACE("Found %p in unused list\n", ret);
3328 list_remove(&ret->entry);
3329 list_add_head(&gdi_font_list, &ret->entry);
3330 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3331 hflist->hfont = hfont;
3332 list_add_head(&ret->hfontlist, &hflist->entry);
3333 return ret;
3336 return NULL;
3339 static void add_to_cache(GdiFont *font)
3341 static DWORD cache_num = 1;
3343 font->cache_num = cache_num++;
3344 list_add_head(&gdi_font_list, &font->entry);
3347 /*************************************************************
3348 * create_child_font_list
3350 static BOOL create_child_font_list(GdiFont *font)
3352 BOOL ret = FALSE;
3353 SYSTEM_LINKS *font_link;
3354 CHILD_FONT *font_link_entry, *new_child;
3355 FontSubst *psub;
3356 WCHAR* font_name;
3358 psub = get_font_subst(&font_subst_list, font->name, -1);
3359 font_name = psub ? psub->to.name : font->name;
3360 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3362 if(!strcmpiW(font_link->font_name, font_name))
3364 TRACE("found entry in system list\n");
3365 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3367 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3368 new_child->face = font_link_entry->face;
3369 new_child->font = NULL;
3370 list_add_tail(&font->child_fonts, &new_child->entry);
3371 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3373 ret = TRUE;
3374 break;
3378 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3379 * Sans Serif. This is how asian windows get default fallbacks for fonts
3381 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3382 font->charset != OEM_CHARSET &&
3383 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3384 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3386 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3388 TRACE("found entry in default fallback list\n");
3389 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3391 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3392 new_child->face = font_link_entry->face;
3393 new_child->font = NULL;
3394 list_add_tail(&font->child_fonts, &new_child->entry);
3395 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3397 ret = TRUE;
3398 break;
3402 return ret;
3405 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3407 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3409 if (pFT_Set_Charmap)
3411 FT_Int i;
3412 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3414 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3416 for (i = 0; i < ft_face->num_charmaps; i++)
3418 if (ft_face->charmaps[i]->encoding == encoding)
3420 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3421 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3423 switch (ft_face->charmaps[i]->platform_id)
3425 default:
3426 cmap_def = ft_face->charmaps[i];
3427 break;
3428 case 0: /* Apple Unicode */
3429 cmap0 = ft_face->charmaps[i];
3430 break;
3431 case 1: /* Macintosh */
3432 cmap1 = ft_face->charmaps[i];
3433 break;
3434 case 2: /* ISO */
3435 cmap2 = ft_face->charmaps[i];
3436 break;
3437 case 3: /* Microsoft */
3438 cmap3 = ft_face->charmaps[i];
3439 break;
3443 if (cmap3) /* prefer Microsoft cmap table */
3444 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3445 else if (cmap1)
3446 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3447 else if (cmap2)
3448 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3449 else if (cmap0)
3450 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3451 else if (cmap_def)
3452 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3454 return ft_err == FT_Err_Ok;
3457 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3460 /*************************************************************
3461 * WineEngCreateFontInstance
3464 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3466 GdiFont *ret;
3467 Face *face, *best, *best_bitmap;
3468 Family *family, *last_resort_family;
3469 struct list *family_elem_ptr, *face_elem_ptr;
3470 INT height, width = 0;
3471 unsigned int score = 0, new_score;
3472 signed int diff = 0, newdiff;
3473 BOOL bd, it, can_use_bitmap;
3474 LOGFONTW lf;
3475 CHARSETINFO csi;
3476 HFONTLIST *hflist;
3477 FMAT2 dcmat;
3478 FontSubst *psub = NULL;
3480 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3481 lf.lfWidth = abs(lf.lfWidth);
3483 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3485 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3486 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3487 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3488 lf.lfEscapement);
3490 if(dc->GraphicsMode == GM_ADVANCED)
3491 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3492 else
3494 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3495 font scaling abilities. */
3496 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3497 dcmat.eM21 = dcmat.eM12 = 0;
3500 /* Try to avoid not necessary glyph transformations */
3501 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3503 lf.lfHeight *= fabs(dcmat.eM11);
3504 lf.lfWidth *= fabs(dcmat.eM11);
3505 dcmat.eM11 = dcmat.eM22 = 1.0;
3508 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3509 dcmat.eM21, dcmat.eM22);
3511 GDI_CheckNotLock();
3512 EnterCriticalSection( &freetype_cs );
3514 /* check the cache first */
3515 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3516 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3517 LeaveCriticalSection( &freetype_cs );
3518 return ret;
3521 TRACE("not in cache\n");
3522 if(list_empty(&font_list)) /* No fonts installed */
3524 TRACE("No fonts installed\n");
3525 LeaveCriticalSection( &freetype_cs );
3526 return NULL;
3529 ret = alloc_font();
3531 ret->font_desc.matrix = dcmat;
3532 ret->font_desc.lf = lf;
3533 ret->font_desc.can_use_bitmap = can_use_bitmap;
3534 calc_hash(&ret->font_desc);
3535 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3536 hflist->hfont = hfont;
3537 list_add_head(&ret->hfontlist, &hflist->entry);
3539 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3540 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3541 original value lfCharSet. Note this is a special case for
3542 Symbol and doesn't happen at least for "Wingdings*" */
3544 if(!strcmpiW(lf.lfFaceName, SymbolW))
3545 lf.lfCharSet = SYMBOL_CHARSET;
3547 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3548 switch(lf.lfCharSet) {
3549 case DEFAULT_CHARSET:
3550 csi.fs.fsCsb[0] = 0;
3551 break;
3552 default:
3553 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3554 csi.fs.fsCsb[0] = 0;
3555 break;
3559 family = NULL;
3560 if(lf.lfFaceName[0] != '\0') {
3561 SYSTEM_LINKS *font_link;
3562 CHILD_FONT *font_link_entry;
3563 LPWSTR FaceName = lf.lfFaceName;
3566 * Check for a leading '@' this signals that the font is being
3567 * requested in tategaki mode (vertical writing substitution) but
3568 * does not affect the fontface that is to be selected.
3570 if (lf.lfFaceName[0]=='@')
3571 FaceName = &lf.lfFaceName[1];
3573 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3575 if(psub) {
3576 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3577 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3578 if (psub->to.charset != -1)
3579 lf.lfCharSet = psub->to.charset;
3582 /* We want a match on name and charset or just name if
3583 charset was DEFAULT_CHARSET. If the latter then
3584 we fixup the returned charset later in get_nearest_charset
3585 where we'll either use the charset of the current ansi codepage
3586 or if that's unavailable the first charset that the font supports.
3588 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3589 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3590 if (!strcmpiW(family->FamilyName, FaceName) ||
3591 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3593 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3594 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3595 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3596 if(face->scalable || can_use_bitmap)
3597 goto found;
3603 * Try check the SystemLink list first for a replacement font.
3604 * We may find good replacements there.
3606 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3608 if(!strcmpiW(font_link->font_name, FaceName) ||
3609 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3611 TRACE("found entry in system list\n");
3612 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3614 face = font_link_entry->face;
3615 family = face->family;
3616 if(csi.fs.fsCsb[0] &
3617 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3619 if(face->scalable || can_use_bitmap)
3620 goto found;
3627 psub = NULL; /* substitution is no more relevant */
3629 /* If requested charset was DEFAULT_CHARSET then try using charset
3630 corresponding to the current ansi codepage */
3631 if (!csi.fs.fsCsb[0])
3633 INT acp = GetACP();
3634 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3635 FIXME("TCI failed on codepage %d\n", acp);
3636 csi.fs.fsCsb[0] = 0;
3637 } else
3638 lf.lfCharSet = csi.ciCharset;
3641 /* Face families are in the top 4 bits of lfPitchAndFamily,
3642 so mask with 0xF0 before testing */
3644 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3645 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3646 strcpyW(lf.lfFaceName, defFixed);
3647 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3648 strcpyW(lf.lfFaceName, defSerif);
3649 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3650 strcpyW(lf.lfFaceName, defSans);
3651 else
3652 strcpyW(lf.lfFaceName, defSans);
3653 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3654 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3655 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3656 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3657 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3658 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3659 if(face->scalable || can_use_bitmap)
3660 goto found;
3665 last_resort_family = NULL;
3666 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3667 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3668 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3669 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3670 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3671 if(face->scalable)
3672 goto found;
3673 if(can_use_bitmap && !last_resort_family)
3674 last_resort_family = family;
3679 if(last_resort_family) {
3680 family = last_resort_family;
3681 csi.fs.fsCsb[0] = 0;
3682 goto found;
3685 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3686 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3687 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3688 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3689 if(face->scalable) {
3690 csi.fs.fsCsb[0] = 0;
3691 WARN("just using first face for now\n");
3692 goto found;
3694 if(can_use_bitmap && !last_resort_family)
3695 last_resort_family = family;
3698 if(!last_resort_family) {
3699 FIXME("can't find a single appropriate font - bailing\n");
3700 free_font(ret);
3701 LeaveCriticalSection( &freetype_cs );
3702 return NULL;
3705 WARN("could only find a bitmap font - this will probably look awful!\n");
3706 family = last_resort_family;
3707 csi.fs.fsCsb[0] = 0;
3709 found:
3710 it = lf.lfItalic ? 1 : 0;
3711 bd = lf.lfWeight > 550 ? 1 : 0;
3713 height = lf.lfHeight;
3715 face = best = best_bitmap = NULL;
3716 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3718 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3720 BOOL italic, bold;
3722 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3723 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3724 new_score = (italic ^ it) + (bold ^ bd);
3725 if(!best || new_score <= score)
3727 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3728 italic, bold, it, bd);
3729 score = new_score;
3730 best = face;
3731 if(best->scalable && score == 0) break;
3732 if(!best->scalable)
3734 if(height > 0)
3735 newdiff = height - (signed int)(best->size.height);
3736 else
3737 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3738 if(!best_bitmap || new_score < score ||
3739 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3741 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3742 diff = newdiff;
3743 best_bitmap = best;
3744 if(score == 0 && diff == 0) break;
3750 if(best)
3751 face = best->scalable ? best : best_bitmap;
3752 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3753 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3755 ret->fs = face->fs;
3757 if(csi.fs.fsCsb[0]) {
3758 ret->charset = lf.lfCharSet;
3759 ret->codepage = csi.ciACP;
3761 else
3762 ret->charset = get_nearest_charset(face, &ret->codepage);
3764 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3765 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3767 ret->aveWidth = height ? lf.lfWidth : 0;
3769 if(!face->scalable) {
3770 /* Windows uses integer scaling factors for bitmap fonts */
3771 INT scale, scaled_height;
3772 GdiFont *cachedfont;
3774 /* FIXME: rotation of bitmap fonts is ignored */
3775 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3776 if (ret->aveWidth)
3777 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3778 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3779 dcmat.eM11 = dcmat.eM22 = 1.0;
3780 /* As we changed the matrix, we need to search the cache for the font again,
3781 * otherwise we might explode the cache. */
3782 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3783 TRACE("Found cached font after non-scalable matrix rescale!\n");
3784 free_font( ret );
3785 LeaveCriticalSection( &freetype_cs );
3786 return cachedfont;
3788 calc_hash(&ret->font_desc);
3790 if (height != 0) height = diff;
3791 height += face->size.height;
3793 scale = (height + face->size.height - 1) / face->size.height;
3794 scaled_height = scale * face->size.height;
3795 /* Only jump to the next height if the difference <= 25% original height */
3796 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3797 /* The jump between unscaled and doubled is delayed by 1 */
3798 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3799 ret->scale_y = scale;
3801 width = face->size.x_ppem >> 6;
3802 height = face->size.y_ppem >> 6;
3804 else
3805 ret->scale_y = 1.0;
3806 TRACE("font scale y: %f\n", ret->scale_y);
3808 ret->ft_face = OpenFontFace(ret, face, width, height);
3810 if (!ret->ft_face)
3812 free_font( ret );
3813 LeaveCriticalSection( &freetype_cs );
3814 return 0;
3817 ret->ntmFlags = face->ntmFlags;
3819 if (ret->charset == SYMBOL_CHARSET &&
3820 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3821 /* No ops */
3823 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3824 /* No ops */
3826 else {
3827 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3830 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3831 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3832 ret->underline = lf.lfUnderline ? 0xff : 0;
3833 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3834 create_child_font_list(ret);
3836 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3838 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3839 if (length != GDI_ERROR)
3841 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3842 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3843 TRACE("Loaded GSUB table of %i bytes\n",length);
3847 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3849 add_to_cache(ret);
3850 LeaveCriticalSection( &freetype_cs );
3851 return ret;
3854 static void dump_gdi_font_list(void)
3856 GdiFont *gdiFont;
3857 struct list *elem_ptr;
3859 TRACE("---------- gdiFont Cache ----------\n");
3860 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3861 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3862 TRACE("gdiFont=%p %s %d\n",
3863 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3866 TRACE("---------- Unused gdiFont Cache ----------\n");
3867 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3868 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3869 TRACE("gdiFont=%p %s %d\n",
3870 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3873 TRACE("---------- Child gdiFont Cache ----------\n");
3874 LIST_FOR_EACH(elem_ptr, &child_font_list) {
3875 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3876 TRACE("gdiFont=%p %s %d\n",
3877 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3881 /*************************************************************
3882 * WineEngDestroyFontInstance
3884 * free the gdiFont associated with this handle
3887 BOOL WineEngDestroyFontInstance(HFONT handle)
3889 GdiFont *gdiFont;
3890 HFONTLIST *hflist;
3891 BOOL ret = FALSE;
3892 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3893 int i = 0;
3895 GDI_CheckNotLock();
3896 EnterCriticalSection( &freetype_cs );
3898 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3900 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3901 while(hfontlist_elem_ptr) {
3902 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3903 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3904 if(hflist->hfont == handle) {
3905 TRACE("removing child font %p from child list\n", gdiFont);
3906 list_remove(&gdiFont->entry);
3907 LeaveCriticalSection( &freetype_cs );
3908 return TRUE;
3913 TRACE("destroying hfont=%p\n", handle);
3914 if(TRACE_ON(font))
3915 dump_gdi_font_list();
3917 font_elem_ptr = list_head(&gdi_font_list);
3918 while(font_elem_ptr) {
3919 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3920 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3922 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3923 while(hfontlist_elem_ptr) {
3924 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3925 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3926 if(hflist->hfont == handle) {
3927 list_remove(&hflist->entry);
3928 HeapFree(GetProcessHeap(), 0, hflist);
3929 ret = TRUE;
3932 if(list_empty(&gdiFont->hfontlist)) {
3933 TRACE("Moving to Unused list\n");
3934 list_remove(&gdiFont->entry);
3935 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3940 font_elem_ptr = list_head(&unused_gdi_font_list);
3941 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3942 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3943 while(font_elem_ptr) {
3944 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3945 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3946 TRACE("freeing %p\n", gdiFont);
3947 list_remove(&gdiFont->entry);
3948 free_font(gdiFont);
3950 LeaveCriticalSection( &freetype_cs );
3951 return ret;
3954 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3955 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3957 GdiFont *font;
3958 LONG width, height;
3960 if (face->cached_enum_data)
3962 TRACE("Cached\n");
3963 *pelf = face->cached_enum_data->elf;
3964 *pntm = face->cached_enum_data->ntm;
3965 *ptype = face->cached_enum_data->type;
3966 return;
3969 font = alloc_font();
3971 if(face->scalable) {
3972 height = -2048; /* 2048 is the most common em size */
3973 width = 0;
3974 } else {
3975 height = face->size.y_ppem >> 6;
3976 width = face->size.x_ppem >> 6;
3978 font->scale_y = 1.0;
3980 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3982 free_font(font);
3983 return;
3986 font->name = strdupW(face->family->FamilyName);
3987 font->ntmFlags = face->ntmFlags;
3989 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3991 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3993 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3995 lstrcpynW(pelf->elfLogFont.lfFaceName,
3996 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3997 LF_FACESIZE);
3998 lstrcpynW(pelf->elfFullName,
3999 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4000 LF_FULLFACESIZE);
4001 lstrcpynW(pelf->elfStyle,
4002 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4003 LF_FACESIZE);
4005 else
4007 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4009 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4011 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4012 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4013 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4016 pntm->ntmTm.ntmFlags = face->ntmFlags;
4017 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4018 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4019 pntm->ntmFontSig = face->fs;
4021 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4023 pelf->elfLogFont.lfEscapement = 0;
4024 pelf->elfLogFont.lfOrientation = 0;
4025 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4026 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4027 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4028 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4029 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4030 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4031 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4032 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4033 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4034 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4035 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4037 *ptype = 0;
4038 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4039 *ptype |= TRUETYPE_FONTTYPE;
4040 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4041 *ptype |= DEVICE_FONTTYPE;
4042 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4043 *ptype |= RASTER_FONTTYPE;
4045 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4046 if (face->cached_enum_data)
4048 face->cached_enum_data->elf = *pelf;
4049 face->cached_enum_data->ntm = *pntm;
4050 face->cached_enum_data->type = *ptype;
4053 free_font(font);
4056 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4058 struct list *face_elem_ptr;
4060 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4062 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4064 static const WCHAR spaceW[] = { ' ',0 };
4065 WCHAR full_family_name[LF_FULLFACESIZE];
4066 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4068 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4070 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4071 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4072 continue;
4075 strcpyW(full_family_name, family->FamilyName);
4076 strcatW(full_family_name, spaceW);
4077 strcatW(full_family_name, face->StyleName);
4078 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4081 return FALSE;
4084 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4086 static const WCHAR spaceW[] = { ' ',0 };
4087 WCHAR full_family_name[LF_FULLFACESIZE];
4089 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4091 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4093 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4094 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4095 return FALSE;
4098 strcpyW(full_family_name, face->family->FamilyName);
4099 strcatW(full_family_name, spaceW);
4100 strcatW(full_family_name, face->StyleName);
4101 return !strcmpiW(lf->lfFaceName, full_family_name);
4104 static BOOL enum_face_charsets(Face *face, FONTENUMPROCW proc, LPARAM lparam)
4106 ENUMLOGFONTEXW elf;
4107 NEWTEXTMETRICEXW ntm;
4108 DWORD type = 0;
4109 FONTSIGNATURE fs;
4110 CHARSETINFO csi;
4111 int i;
4113 GetEnumStructs(face, &elf, &ntm, &type);
4114 for(i = 0; i < 32; i++) {
4115 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4116 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4117 strcpyW(elf.elfScript, OEM_DOSW);
4118 i = 32; /* break out of loop */
4119 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4120 continue;
4121 else {
4122 fs.fsCsb[0] = 1L << i;
4123 fs.fsCsb[1] = 0;
4124 if(!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4125 csi.ciCharset = DEFAULT_CHARSET;
4126 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4127 if(csi.ciCharset != DEFAULT_CHARSET) {
4128 elf.elfLogFont.lfCharSet = 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 FALSE;
4144 EnterCriticalSection( &freetype_cs );
4146 return TRUE;
4149 /*************************************************************
4150 * WineEngEnumFonts
4153 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4155 Family *family;
4156 Face *face;
4157 struct list *family_elem_ptr, *face_elem_ptr;
4158 LOGFONTW lf;
4160 if (!plf)
4162 lf.lfCharSet = DEFAULT_CHARSET;
4163 lf.lfPitchAndFamily = 0;
4164 lf.lfFaceName[0] = 0;
4165 plf = &lf;
4168 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4170 GDI_CheckNotLock();
4171 EnterCriticalSection( &freetype_cs );
4172 if(plf->lfFaceName[0]) {
4173 FontSubst *psub;
4174 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4176 if(psub) {
4177 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4178 debugstr_w(psub->to.name));
4179 lf = *plf;
4180 strcpyW(lf.lfFaceName, psub->to.name);
4181 plf = &lf;
4184 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4185 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4186 if(family_matches(family, plf)) {
4187 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4188 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4189 if (!face_matches(face, plf)) continue;
4190 if (!enum_face_charsets(face, proc, lparam)) return 0;
4194 } else {
4195 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4196 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4197 face_elem_ptr = list_head(&family->faces);
4198 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4199 if (!enum_face_charsets(face, proc, lparam)) return 0;
4202 LeaveCriticalSection( &freetype_cs );
4203 return 1;
4206 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4208 pt->x.value = vec->x >> 6;
4209 pt->x.fract = (vec->x & 0x3f) << 10;
4210 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4211 pt->y.value = vec->y >> 6;
4212 pt->y.fract = (vec->y & 0x3f) << 10;
4213 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4214 return;
4217 /***************************************************
4218 * According to the MSDN documentation on WideCharToMultiByte,
4219 * certain codepages cannot set the default_used parameter.
4220 * This returns TRUE if the codepage can set that parameter, false else
4221 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4223 static BOOL codepage_sets_default_used(UINT codepage)
4225 switch (codepage)
4227 case CP_UTF7:
4228 case CP_UTF8:
4229 case CP_SYMBOL:
4230 return FALSE;
4231 default:
4232 return TRUE;
4237 * GSUB Table handling functions
4240 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4242 const GSUB_CoverageFormat1* cf1;
4244 cf1 = table;
4246 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4248 int count = GET_BE_WORD(cf1->GlyphCount);
4249 int i;
4250 TRACE("Coverage Format 1, %i glyphs\n",count);
4251 for (i = 0; i < count; i++)
4252 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4253 return i;
4254 return -1;
4256 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4258 const GSUB_CoverageFormat2* cf2;
4259 int i;
4260 int count;
4261 cf2 = (const GSUB_CoverageFormat2*)cf1;
4263 count = GET_BE_WORD(cf2->RangeCount);
4264 TRACE("Coverage Format 2, %i ranges\n",count);
4265 for (i = 0; i < count; i++)
4267 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4268 return -1;
4269 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4270 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4272 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4273 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4276 return -1;
4278 else
4279 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4281 return -1;
4284 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4286 const GSUB_ScriptList *script;
4287 const GSUB_Script *deflt = NULL;
4288 int i;
4289 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4291 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4292 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4294 const GSUB_Script *scr;
4295 int offset;
4297 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4298 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4300 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4301 return scr;
4302 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4303 deflt = scr;
4305 return deflt;
4308 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4310 int i;
4311 int offset;
4312 const GSUB_LangSys *Lang;
4314 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4316 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4318 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4319 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4321 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4322 return Lang;
4324 offset = GET_BE_WORD(script->DefaultLangSys);
4325 if (offset)
4327 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4328 return Lang;
4330 return NULL;
4333 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4335 int i;
4336 const GSUB_FeatureList *feature;
4337 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4339 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4340 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4342 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4343 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4345 const GSUB_Feature *feat;
4346 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4347 return feat;
4350 return NULL;
4353 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4355 int i;
4356 int offset;
4357 const GSUB_LookupList *lookup;
4358 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4360 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4361 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4363 const GSUB_LookupTable *look;
4364 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4365 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4366 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4367 if (GET_BE_WORD(look->LookupType) != 1)
4368 FIXME("We only handle SubType 1\n");
4369 else
4371 int j;
4373 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4375 const GSUB_SingleSubstFormat1 *ssf1;
4376 offset = GET_BE_WORD(look->SubTable[j]);
4377 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4378 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4380 int offset = GET_BE_WORD(ssf1->Coverage);
4381 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4382 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4384 TRACE(" Glyph 0x%x ->",glyph);
4385 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4386 TRACE(" 0x%x\n",glyph);
4389 else
4391 const GSUB_SingleSubstFormat2 *ssf2;
4392 INT index;
4393 INT offset;
4395 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4396 offset = GET_BE_WORD(ssf1->Coverage);
4397 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4398 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4399 TRACE(" Coverage index %i\n",index);
4400 if (index != -1)
4402 TRACE(" Glyph is 0x%x ->",glyph);
4403 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4404 TRACE("0x%x\n",glyph);
4410 return glyph;
4413 static const char* get_opentype_script(const GdiFont *font)
4416 * I am not sure if this is the correct way to generate our script tag
4419 switch (font->charset)
4421 case ANSI_CHARSET: return "latn";
4422 case BALTIC_CHARSET: return "latn"; /* ?? */
4423 case CHINESEBIG5_CHARSET: return "hani";
4424 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4425 case GB2312_CHARSET: return "hani";
4426 case GREEK_CHARSET: return "grek";
4427 case HANGUL_CHARSET: return "hang";
4428 case RUSSIAN_CHARSET: return "cyrl";
4429 case SHIFTJIS_CHARSET: return "kana";
4430 case TURKISH_CHARSET: return "latn"; /* ?? */
4431 case VIETNAMESE_CHARSET: return "latn";
4432 case JOHAB_CHARSET: return "latn"; /* ?? */
4433 case ARABIC_CHARSET: return "arab";
4434 case HEBREW_CHARSET: return "hebr";
4435 case THAI_CHARSET: return "thai";
4436 default: return "latn";
4440 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4442 const GSUB_Header *header;
4443 const GSUB_Script *script;
4444 const GSUB_LangSys *language;
4445 const GSUB_Feature *feature;
4447 if (!font->GSUB_Table)
4448 return glyph;
4450 header = font->GSUB_Table;
4452 script = GSUB_get_script_table(header, get_opentype_script(font));
4453 if (!script)
4455 TRACE("Script not found\n");
4456 return glyph;
4458 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4459 if (!language)
4461 TRACE("Language not found\n");
4462 return glyph;
4464 feature = GSUB_get_feature(header, language, "vrt2");
4465 if (!feature)
4466 feature = GSUB_get_feature(header, language, "vert");
4467 if (!feature)
4469 TRACE("vrt2/vert feature not found\n");
4470 return glyph;
4472 return GSUB_apply_feature(header, feature, glyph);
4475 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4477 FT_UInt glyphId;
4479 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4480 WCHAR wc = (WCHAR)glyph;
4481 BOOL default_used;
4482 BOOL *default_used_pointer;
4483 FT_UInt ret;
4484 char buf;
4485 default_used_pointer = NULL;
4486 default_used = FALSE;
4487 if (codepage_sets_default_used(font->codepage))
4488 default_used_pointer = &default_used;
4489 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4490 ret = 0;
4491 else
4492 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4493 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4494 return get_GSUB_vert_glyph(font,ret);
4497 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4498 glyph = glyph + 0xf000;
4499 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4500 return get_GSUB_vert_glyph(font,glyphId);
4503 /*************************************************************
4504 * WineEngGetGlyphIndices
4507 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4508 LPWORD pgi, DWORD flags)
4510 int i;
4511 int default_char = -1;
4513 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4515 for(i = 0; i < count; i++)
4517 pgi[i] = get_glyph_index(font, lpstr[i]);
4518 if (pgi[i] == 0)
4520 if (default_char == -1)
4522 if (FT_IS_SFNT(font->ft_face))
4524 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4525 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4527 else
4529 TEXTMETRICW textm;
4530 WineEngGetTextMetrics(font, &textm);
4531 default_char = textm.tmDefaultChar;
4534 pgi[i] = default_char;
4537 return count;
4540 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4542 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4543 return !memcmp(matrix, &identity, sizeof(FMAT2));
4546 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4548 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4549 return !memcmp(matrix, &identity, sizeof(MAT2));
4552 /*************************************************************
4553 * WineEngGetGlyphOutline
4555 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4556 * except that the first parameter is the HWINEENGFONT of the font in
4557 * question rather than an HDC.
4560 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4561 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4562 const MAT2* lpmat)
4564 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4565 FT_Face ft_face = incoming_font->ft_face;
4566 GdiFont *font = incoming_font;
4567 FT_UInt glyph_index;
4568 DWORD width, height, pitch, needed = 0;
4569 FT_Bitmap ft_bitmap;
4570 FT_Error err;
4571 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4572 FT_Angle angle = 0;
4573 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4574 double widthRatio = 1.0;
4575 FT_Matrix transMat = identityMat;
4576 FT_Matrix transMatUnrotated;
4577 BOOL needsTransform = FALSE;
4578 BOOL tategaki = (font->GSUB_Table != NULL);
4579 UINT original_index;
4581 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4582 buflen, buf, lpmat);
4584 TRACE("font transform %f %f %f %f\n",
4585 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4586 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4588 GDI_CheckNotLock();
4589 EnterCriticalSection( &freetype_cs );
4591 if(format & GGO_GLYPH_INDEX) {
4592 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4593 original_index = glyph;
4594 format &= ~GGO_GLYPH_INDEX;
4595 } else {
4596 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4597 ft_face = font->ft_face;
4598 original_index = glyph_index;
4601 if(format & GGO_UNHINTED) {
4602 load_flags |= FT_LOAD_NO_HINTING;
4603 format &= ~GGO_UNHINTED;
4606 /* tategaki never appears to happen to lower glyph index */
4607 if (glyph_index < TATEGAKI_LOWER_BOUND )
4608 tategaki = FALSE;
4610 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4611 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4612 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4613 font->gmsize * sizeof(GM*));
4614 } else {
4615 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4616 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4618 *lpgm = FONT_GM(font,original_index)->gm;
4619 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4620 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4621 lpgm->gmCellIncX, lpgm->gmCellIncY);
4622 LeaveCriticalSection( &freetype_cs );
4623 return 1; /* FIXME */
4627 if (!font->gm[original_index / GM_BLOCK_SIZE])
4628 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4630 /* Scaling factor */
4631 if (font->aveWidth)
4633 TEXTMETRICW tm;
4635 WineEngGetTextMetrics(font, &tm);
4637 widthRatio = (double)font->aveWidth;
4638 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4640 else
4641 widthRatio = font->scale_y;
4643 /* Scaling transform */
4644 if (widthRatio != 1.0 || font->scale_y != 1.0)
4646 FT_Matrix scaleMat;
4647 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4648 scaleMat.xy = 0;
4649 scaleMat.yx = 0;
4650 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4652 pFT_Matrix_Multiply(&scaleMat, &transMat);
4653 needsTransform = TRUE;
4656 /* Slant transform */
4657 if (font->fake_italic) {
4658 FT_Matrix slantMat;
4660 slantMat.xx = (1 << 16);
4661 slantMat.xy = ((1 << 16) >> 2);
4662 slantMat.yx = 0;
4663 slantMat.yy = (1 << 16);
4664 pFT_Matrix_Multiply(&slantMat, &transMat);
4665 needsTransform = TRUE;
4668 /* Rotation transform */
4669 transMatUnrotated = transMat;
4670 if(font->orientation && !tategaki) {
4671 FT_Matrix rotationMat;
4672 FT_Vector vecAngle;
4673 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4674 pFT_Vector_Unit(&vecAngle, angle);
4675 rotationMat.xx = vecAngle.x;
4676 rotationMat.xy = -vecAngle.y;
4677 rotationMat.yx = -rotationMat.xy;
4678 rotationMat.yy = rotationMat.xx;
4680 pFT_Matrix_Multiply(&rotationMat, &transMat);
4681 needsTransform = TRUE;
4684 /* World transform */
4685 if (!is_identity_FMAT2(&font->font_desc.matrix))
4687 FT_Matrix worldMat;
4688 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4689 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4690 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4691 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4692 pFT_Matrix_Multiply(&worldMat, &transMat);
4693 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4694 needsTransform = TRUE;
4697 /* Extra transformation specified by caller */
4698 if (!is_identity_MAT2(lpmat))
4700 FT_Matrix extraMat;
4701 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4702 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4703 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4704 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4705 pFT_Matrix_Multiply(&extraMat, &transMat);
4706 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4707 needsTransform = TRUE;
4710 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4711 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4712 format == GGO_GRAY8_BITMAP))
4714 load_flags |= FT_LOAD_NO_BITMAP;
4717 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4719 if(err) {
4720 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4721 LeaveCriticalSection( &freetype_cs );
4722 return GDI_ERROR;
4725 if(!needsTransform) {
4726 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4727 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4728 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4730 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4731 bottom = (ft_face->glyph->metrics.horiBearingY -
4732 ft_face->glyph->metrics.height) & -64;
4733 lpgm->gmCellIncX = adv;
4734 lpgm->gmCellIncY = 0;
4735 } else {
4736 INT xc, yc;
4737 FT_Vector vec;
4739 left = right = 0;
4741 for(xc = 0; xc < 2; xc++) {
4742 for(yc = 0; yc < 2; yc++) {
4743 vec.x = (ft_face->glyph->metrics.horiBearingX +
4744 xc * ft_face->glyph->metrics.width);
4745 vec.y = ft_face->glyph->metrics.horiBearingY -
4746 yc * ft_face->glyph->metrics.height;
4747 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4748 pFT_Vector_Transform(&vec, &transMat);
4749 if(xc == 0 && yc == 0) {
4750 left = right = vec.x;
4751 top = bottom = vec.y;
4752 } else {
4753 if(vec.x < left) left = vec.x;
4754 else if(vec.x > right) right = vec.x;
4755 if(vec.y < bottom) bottom = vec.y;
4756 else if(vec.y > top) top = vec.y;
4760 left = left & -64;
4761 right = (right + 63) & -64;
4762 bottom = bottom & -64;
4763 top = (top + 63) & -64;
4765 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4766 vec.x = ft_face->glyph->metrics.horiAdvance;
4767 vec.y = 0;
4768 pFT_Vector_Transform(&vec, &transMat);
4769 lpgm->gmCellIncX = (vec.x+63) >> 6;
4770 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4772 vec.x = ft_face->glyph->metrics.horiAdvance;
4773 vec.y = 0;
4774 pFT_Vector_Transform(&vec, &transMatUnrotated);
4775 adv = (vec.x+63) >> 6;
4778 lsb = left >> 6;
4779 bbx = (right - left) >> 6;
4780 lpgm->gmBlackBoxX = (right - left) >> 6;
4781 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4782 lpgm->gmptGlyphOrigin.x = left >> 6;
4783 lpgm->gmptGlyphOrigin.y = top >> 6;
4785 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4786 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4787 lpgm->gmCellIncX, lpgm->gmCellIncY);
4789 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4790 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4792 FONT_GM(font,original_index)->gm = *lpgm;
4793 FONT_GM(font,original_index)->adv = adv;
4794 FONT_GM(font,original_index)->lsb = lsb;
4795 FONT_GM(font,original_index)->bbx = bbx;
4796 FONT_GM(font,original_index)->init = TRUE;
4799 if(format == GGO_METRICS)
4801 LeaveCriticalSection( &freetype_cs );
4802 return 1; /* FIXME */
4805 if(ft_face->glyph->format != ft_glyph_format_outline &&
4806 (format == GGO_NATIVE || format == GGO_BEZIER ||
4807 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4808 format == GGO_GRAY8_BITMAP))
4810 TRACE("loaded a bitmap\n");
4811 LeaveCriticalSection( &freetype_cs );
4812 return GDI_ERROR;
4815 switch(format) {
4816 case GGO_BITMAP:
4817 width = lpgm->gmBlackBoxX;
4818 height = lpgm->gmBlackBoxY;
4819 pitch = ((width + 31) >> 5) << 2;
4820 needed = pitch * height;
4822 if(!buf || !buflen) break;
4824 switch(ft_face->glyph->format) {
4825 case ft_glyph_format_bitmap:
4827 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4828 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4829 INT h = ft_face->glyph->bitmap.rows;
4830 while(h--) {
4831 memcpy(dst, src, w);
4832 src += ft_face->glyph->bitmap.pitch;
4833 dst += pitch;
4835 break;
4838 case ft_glyph_format_outline:
4839 ft_bitmap.width = width;
4840 ft_bitmap.rows = height;
4841 ft_bitmap.pitch = pitch;
4842 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4843 ft_bitmap.buffer = buf;
4845 if(needsTransform)
4846 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4848 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4850 /* Note: FreeType will only set 'black' bits for us. */
4851 memset(buf, 0, needed);
4852 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4853 break;
4855 default:
4856 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4857 LeaveCriticalSection( &freetype_cs );
4858 return GDI_ERROR;
4860 break;
4862 case GGO_GRAY2_BITMAP:
4863 case GGO_GRAY4_BITMAP:
4864 case GGO_GRAY8_BITMAP:
4865 case WINE_GGO_GRAY16_BITMAP:
4867 unsigned int mult, row, col;
4868 BYTE *start, *ptr;
4870 width = lpgm->gmBlackBoxX;
4871 height = lpgm->gmBlackBoxY;
4872 pitch = (width + 3) / 4 * 4;
4873 needed = pitch * height;
4875 if(!buf || !buflen) break;
4877 switch(ft_face->glyph->format) {
4878 case ft_glyph_format_bitmap:
4880 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4881 INT h = ft_face->glyph->bitmap.rows;
4882 INT x;
4883 while(h--) {
4884 for(x = 0; x < pitch; x++)
4886 if(x < ft_face->glyph->bitmap.width)
4887 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4888 else
4889 dst[x] = 0;
4891 src += ft_face->glyph->bitmap.pitch;
4892 dst += pitch;
4894 LeaveCriticalSection( &freetype_cs );
4895 return needed;
4897 case ft_glyph_format_outline:
4899 ft_bitmap.width = width;
4900 ft_bitmap.rows = height;
4901 ft_bitmap.pitch = pitch;
4902 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4903 ft_bitmap.buffer = buf;
4905 if(needsTransform)
4906 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4908 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4910 memset(ft_bitmap.buffer, 0, buflen);
4912 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4914 if(format == GGO_GRAY2_BITMAP)
4915 mult = 4;
4916 else if(format == GGO_GRAY4_BITMAP)
4917 mult = 16;
4918 else if(format == GGO_GRAY8_BITMAP)
4919 mult = 64;
4920 else /* format == WINE_GGO_GRAY16_BITMAP */
4922 LeaveCriticalSection( &freetype_cs );
4923 return needed;
4925 break;
4927 default:
4928 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4929 LeaveCriticalSection( &freetype_cs );
4930 return GDI_ERROR;
4933 start = buf;
4934 for(row = 0; row < height; row++) {
4935 ptr = start;
4936 for(col = 0; col < width; col++, ptr++) {
4937 *ptr = (((int)*ptr) * mult + 128) / 256;
4939 start += pitch;
4941 break;
4944 case WINE_GGO_HRGB_BITMAP:
4945 case WINE_GGO_HBGR_BITMAP:
4946 case WINE_GGO_VRGB_BITMAP:
4947 case WINE_GGO_VBGR_BITMAP:
4948 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4950 switch (ft_face->glyph->format)
4952 case FT_GLYPH_FORMAT_BITMAP:
4954 BYTE *src, *dst;
4955 INT src_pitch, x;
4957 width = lpgm->gmBlackBoxX;
4958 height = lpgm->gmBlackBoxY;
4959 pitch = width * 4;
4960 needed = pitch * height;
4962 if (!buf || !buflen) break;
4964 memset(buf, 0, buflen);
4965 dst = buf;
4966 src = ft_face->glyph->bitmap.buffer;
4967 src_pitch = ft_face->glyph->bitmap.pitch;
4969 while ( height-- )
4971 for (x = 0; x < width; x++)
4973 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4974 ((unsigned int *)dst)[x] = ~0u;
4976 src += src_pitch;
4977 dst += pitch;
4980 break;
4983 case FT_GLYPH_FORMAT_OUTLINE:
4985 unsigned int *dst;
4986 BYTE *src;
4987 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4988 INT x_shift, y_shift;
4989 BOOL rgb;
4990 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4991 FT_Render_Mode render_mode =
4992 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4993 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4995 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4997 if ( render_mode == FT_RENDER_MODE_LCD)
4999 lpgm->gmBlackBoxX += 2;
5000 lpgm->gmptGlyphOrigin.x -= 1;
5002 else
5004 lpgm->gmBlackBoxY += 2;
5005 lpgm->gmptGlyphOrigin.y += 1;
5009 width = lpgm->gmBlackBoxX;
5010 height = lpgm->gmBlackBoxY;
5011 pitch = width * 4;
5012 needed = pitch * height;
5014 if (!buf || !buflen) break;
5016 memset(buf, 0, buflen);
5017 dst = buf;
5018 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5020 if ( needsTransform )
5021 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5023 if ( pFT_Library_SetLcdFilter )
5024 pFT_Library_SetLcdFilter( library, lcdfilter );
5025 pFT_Render_Glyph (ft_face->glyph, render_mode);
5027 src = ft_face->glyph->bitmap.buffer;
5028 src_pitch = ft_face->glyph->bitmap.pitch;
5029 src_width = ft_face->glyph->bitmap.width;
5030 src_height = ft_face->glyph->bitmap.rows;
5032 if ( render_mode == FT_RENDER_MODE_LCD)
5034 rgb_interval = 1;
5035 hmul = 3;
5036 vmul = 1;
5038 else
5040 rgb_interval = src_pitch;
5041 hmul = 1;
5042 vmul = 3;
5045 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5046 if ( x_shift < 0 ) x_shift = 0;
5047 if ( x_shift + (src_width / hmul) > width )
5048 x_shift = width - (src_width / hmul);
5050 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5051 if ( y_shift < 0 ) y_shift = 0;
5052 if ( y_shift + (src_height / vmul) > height )
5053 y_shift = height - (src_height / vmul);
5055 dst += x_shift + y_shift * ( pitch / 4 );
5056 while ( src_height )
5058 for ( x = 0; x < src_width / hmul; x++ )
5060 if ( rgb )
5062 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5063 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5064 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5065 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5067 else
5069 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5070 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5071 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5072 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5075 src += src_pitch * vmul;
5076 dst += pitch / 4;
5077 src_height -= vmul;
5080 break;
5083 default:
5084 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5085 LeaveCriticalSection ( &freetype_cs );
5086 return GDI_ERROR;
5089 break;
5091 #else
5092 LeaveCriticalSection( &freetype_cs );
5093 return GDI_ERROR;
5094 #endif
5096 case GGO_NATIVE:
5098 int contour, point = 0, first_pt;
5099 FT_Outline *outline = &ft_face->glyph->outline;
5100 TTPOLYGONHEADER *pph;
5101 TTPOLYCURVE *ppc;
5102 DWORD pph_start, cpfx, type;
5104 if(buflen == 0) buf = NULL;
5106 if (needsTransform && buf) {
5107 pFT_Outline_Transform(outline, &transMat);
5110 for(contour = 0; contour < outline->n_contours; contour++) {
5111 pph_start = needed;
5112 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5113 first_pt = point;
5114 if(buf) {
5115 pph->dwType = TT_POLYGON_TYPE;
5116 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5118 needed += sizeof(*pph);
5119 point++;
5120 while(point <= outline->contours[contour]) {
5121 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5122 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5123 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5124 cpfx = 0;
5125 do {
5126 if(buf)
5127 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5128 cpfx++;
5129 point++;
5130 } while(point <= outline->contours[contour] &&
5131 (outline->tags[point] & FT_Curve_Tag_On) ==
5132 (outline->tags[point-1] & FT_Curve_Tag_On));
5133 /* At the end of a contour Windows adds the start point, but
5134 only for Beziers */
5135 if(point > outline->contours[contour] &&
5136 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5137 if(buf)
5138 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5139 cpfx++;
5140 } else if(point <= outline->contours[contour] &&
5141 outline->tags[point] & FT_Curve_Tag_On) {
5142 /* add closing pt for bezier */
5143 if(buf)
5144 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5145 cpfx++;
5146 point++;
5148 if(buf) {
5149 ppc->wType = type;
5150 ppc->cpfx = cpfx;
5152 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5154 if(buf)
5155 pph->cb = needed - pph_start;
5157 break;
5159 case GGO_BEZIER:
5161 /* Convert the quadratic Beziers to cubic Beziers.
5162 The parametric eqn for a cubic Bezier is, from PLRM:
5163 r(t) = at^3 + bt^2 + ct + r0
5164 with the control points:
5165 r1 = r0 + c/3
5166 r2 = r1 + (c + b)/3
5167 r3 = r0 + c + b + a
5169 A quadratic Beizer has the form:
5170 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5172 So equating powers of t leads to:
5173 r1 = 2/3 p1 + 1/3 p0
5174 r2 = 2/3 p1 + 1/3 p2
5175 and of course r0 = p0, r3 = p2
5178 int contour, point = 0, first_pt;
5179 FT_Outline *outline = &ft_face->glyph->outline;
5180 TTPOLYGONHEADER *pph;
5181 TTPOLYCURVE *ppc;
5182 DWORD pph_start, cpfx, type;
5183 FT_Vector cubic_control[4];
5184 if(buflen == 0) buf = NULL;
5186 if (needsTransform && buf) {
5187 pFT_Outline_Transform(outline, &transMat);
5190 for(contour = 0; contour < outline->n_contours; contour++) {
5191 pph_start = needed;
5192 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5193 first_pt = point;
5194 if(buf) {
5195 pph->dwType = TT_POLYGON_TYPE;
5196 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5198 needed += sizeof(*pph);
5199 point++;
5200 while(point <= outline->contours[contour]) {
5201 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5202 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5203 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5204 cpfx = 0;
5205 do {
5206 if(type == TT_PRIM_LINE) {
5207 if(buf)
5208 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5209 cpfx++;
5210 point++;
5211 } else {
5212 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5213 so cpfx = 3n */
5215 /* FIXME: Possible optimization in endpoint calculation
5216 if there are two consecutive curves */
5217 cubic_control[0] = outline->points[point-1];
5218 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5219 cubic_control[0].x += outline->points[point].x + 1;
5220 cubic_control[0].y += outline->points[point].y + 1;
5221 cubic_control[0].x >>= 1;
5222 cubic_control[0].y >>= 1;
5224 if(point+1 > outline->contours[contour])
5225 cubic_control[3] = outline->points[first_pt];
5226 else {
5227 cubic_control[3] = outline->points[point+1];
5228 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5229 cubic_control[3].x += outline->points[point].x + 1;
5230 cubic_control[3].y += outline->points[point].y + 1;
5231 cubic_control[3].x >>= 1;
5232 cubic_control[3].y >>= 1;
5235 /* r1 = 1/3 p0 + 2/3 p1
5236 r2 = 1/3 p2 + 2/3 p1 */
5237 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5238 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5239 cubic_control[2] = cubic_control[1];
5240 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5241 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5242 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5243 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5244 if(buf) {
5245 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5246 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5247 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5249 cpfx += 3;
5250 point++;
5252 } while(point <= outline->contours[contour] &&
5253 (outline->tags[point] & FT_Curve_Tag_On) ==
5254 (outline->tags[point-1] & FT_Curve_Tag_On));
5255 /* At the end of a contour Windows adds the start point,
5256 but only for Beziers and we've already done that.
5258 if(point <= outline->contours[contour] &&
5259 outline->tags[point] & FT_Curve_Tag_On) {
5260 /* This is the closing pt of a bezier, but we've already
5261 added it, so just inc point and carry on */
5262 point++;
5264 if(buf) {
5265 ppc->wType = type;
5266 ppc->cpfx = cpfx;
5268 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5270 if(buf)
5271 pph->cb = needed - pph_start;
5273 break;
5276 default:
5277 FIXME("Unsupported format %d\n", format);
5278 LeaveCriticalSection( &freetype_cs );
5279 return GDI_ERROR;
5281 LeaveCriticalSection( &freetype_cs );
5282 return needed;
5285 static BOOL get_bitmap_text_metrics(GdiFont *font)
5287 FT_Face ft_face = font->ft_face;
5288 #ifdef HAVE_FREETYPE_FTWINFNT_H
5289 FT_WinFNT_HeaderRec winfnt_header;
5290 #endif
5291 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5292 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5293 font->potm->otmSize = size;
5295 #define TM font->potm->otmTextMetrics
5296 #ifdef HAVE_FREETYPE_FTWINFNT_H
5297 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5299 TM.tmHeight = winfnt_header.pixel_height;
5300 TM.tmAscent = winfnt_header.ascent;
5301 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5302 TM.tmInternalLeading = winfnt_header.internal_leading;
5303 TM.tmExternalLeading = winfnt_header.external_leading;
5304 TM.tmAveCharWidth = winfnt_header.avg_width;
5305 TM.tmMaxCharWidth = winfnt_header.max_width;
5306 TM.tmWeight = winfnt_header.weight;
5307 TM.tmOverhang = 0;
5308 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5309 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5310 TM.tmFirstChar = winfnt_header.first_char;
5311 TM.tmLastChar = winfnt_header.last_char;
5312 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5313 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5314 TM.tmItalic = winfnt_header.italic;
5315 TM.tmUnderlined = font->underline;
5316 TM.tmStruckOut = font->strikeout;
5317 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5318 TM.tmCharSet = winfnt_header.charset;
5320 else
5321 #endif
5323 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5324 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5325 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5326 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5327 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5328 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5329 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5330 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5331 TM.tmOverhang = 0;
5332 TM.tmDigitizedAspectX = 96; /* FIXME */
5333 TM.tmDigitizedAspectY = 96; /* FIXME */
5334 TM.tmFirstChar = 1;
5335 TM.tmLastChar = 255;
5336 TM.tmDefaultChar = 32;
5337 TM.tmBreakChar = 32;
5338 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5339 TM.tmUnderlined = font->underline;
5340 TM.tmStruckOut = font->strikeout;
5341 /* NB inverted meaning of TMPF_FIXED_PITCH */
5342 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5343 TM.tmCharSet = font->charset;
5345 #undef TM
5347 return TRUE;
5351 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5353 double scale_x, scale_y;
5355 if (font->aveWidth)
5357 scale_x = (double)font->aveWidth;
5358 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5360 else
5361 scale_x = font->scale_y;
5363 scale_x *= fabs(font->font_desc.matrix.eM11);
5364 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5366 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5367 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5369 SCALE_Y(ptm->tmHeight);
5370 SCALE_Y(ptm->tmAscent);
5371 SCALE_Y(ptm->tmDescent);
5372 SCALE_Y(ptm->tmInternalLeading);
5373 SCALE_Y(ptm->tmExternalLeading);
5374 SCALE_Y(ptm->tmOverhang);
5376 SCALE_X(ptm->tmAveCharWidth);
5377 SCALE_X(ptm->tmMaxCharWidth);
5379 #undef SCALE_X
5380 #undef SCALE_Y
5383 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5385 double scale_x, scale_y;
5387 if (font->aveWidth)
5389 scale_x = (double)font->aveWidth;
5390 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5392 else
5393 scale_x = font->scale_y;
5395 scale_x *= fabs(font->font_desc.matrix.eM11);
5396 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5398 scale_font_metrics(font, &potm->otmTextMetrics);
5400 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5401 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5403 SCALE_Y(potm->otmAscent);
5404 SCALE_Y(potm->otmDescent);
5405 SCALE_Y(potm->otmLineGap);
5406 SCALE_Y(potm->otmsCapEmHeight);
5407 SCALE_Y(potm->otmsXHeight);
5408 SCALE_Y(potm->otmrcFontBox.top);
5409 SCALE_Y(potm->otmrcFontBox.bottom);
5410 SCALE_X(potm->otmrcFontBox.left);
5411 SCALE_X(potm->otmrcFontBox.right);
5412 SCALE_Y(potm->otmMacAscent);
5413 SCALE_Y(potm->otmMacDescent);
5414 SCALE_Y(potm->otmMacLineGap);
5415 SCALE_X(potm->otmptSubscriptSize.x);
5416 SCALE_Y(potm->otmptSubscriptSize.y);
5417 SCALE_X(potm->otmptSubscriptOffset.x);
5418 SCALE_Y(potm->otmptSubscriptOffset.y);
5419 SCALE_X(potm->otmptSuperscriptSize.x);
5420 SCALE_Y(potm->otmptSuperscriptSize.y);
5421 SCALE_X(potm->otmptSuperscriptOffset.x);
5422 SCALE_Y(potm->otmptSuperscriptOffset.y);
5423 SCALE_Y(potm->otmsStrikeoutSize);
5424 SCALE_Y(potm->otmsStrikeoutPosition);
5425 SCALE_Y(potm->otmsUnderscoreSize);
5426 SCALE_Y(potm->otmsUnderscorePosition);
5428 #undef SCALE_X
5429 #undef SCALE_Y
5432 /*************************************************************
5433 * WineEngGetTextMetrics
5436 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5438 GDI_CheckNotLock();
5439 EnterCriticalSection( &freetype_cs );
5440 if(!font->potm) {
5441 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5442 if(!get_bitmap_text_metrics(font))
5444 LeaveCriticalSection( &freetype_cs );
5445 return FALSE;
5448 /* Make sure that the font has sane width/height ratio */
5449 if (font->aveWidth)
5451 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5453 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5454 font->aveWidth = 0;
5459 *ptm = font->potm->otmTextMetrics;
5460 scale_font_metrics(font, ptm);
5461 LeaveCriticalSection( &freetype_cs );
5462 return TRUE;
5465 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5467 int i;
5469 for(i = 0; i < ft_face->num_charmaps; i++)
5471 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5472 return TRUE;
5474 return FALSE;
5477 /*************************************************************
5478 * WineEngGetOutlineTextMetrics
5481 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5482 OUTLINETEXTMETRICW *potm)
5484 FT_Face ft_face = font->ft_face;
5485 UINT needed, lenfam, lensty, ret;
5486 TT_OS2 *pOS2;
5487 TT_HoriHeader *pHori;
5488 TT_Postscript *pPost;
5489 FT_Fixed x_scale, y_scale;
5490 WCHAR *family_nameW, *style_nameW;
5491 static const WCHAR spaceW[] = {' ', '\0'};
5492 char *cp;
5493 INT ascent, descent;
5495 TRACE("font=%p\n", font);
5497 if(!FT_IS_SCALABLE(ft_face))
5498 return 0;
5500 GDI_CheckNotLock();
5501 EnterCriticalSection( &freetype_cs );
5503 if(font->potm) {
5504 if(cbSize >= font->potm->otmSize)
5506 memcpy(potm, font->potm, font->potm->otmSize);
5507 scale_outline_font_metrics(font, potm);
5509 LeaveCriticalSection( &freetype_cs );
5510 return font->potm->otmSize;
5514 needed = sizeof(*potm);
5516 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5517 family_nameW = strdupW(font->name);
5519 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5520 * sizeof(WCHAR);
5521 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5522 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5523 style_nameW, lensty/sizeof(WCHAR));
5525 /* These names should be read from the TT name table */
5527 /* length of otmpFamilyName */
5528 needed += lenfam;
5530 /* length of otmpFaceName */
5531 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5532 needed += lenfam; /* just the family name */
5533 } else {
5534 needed += lenfam + lensty; /* family + " " + style */
5537 /* length of otmpStyleName */
5538 needed += lensty;
5540 /* length of otmpFullName */
5541 needed += lenfam + lensty;
5544 x_scale = ft_face->size->metrics.x_scale;
5545 y_scale = ft_face->size->metrics.y_scale;
5547 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5548 if(!pOS2) {
5549 FIXME("Can't find OS/2 table - not TT font?\n");
5550 ret = 0;
5551 goto end;
5554 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5555 if(!pHori) {
5556 FIXME("Can't find HHEA table - not TT font?\n");
5557 ret = 0;
5558 goto end;
5561 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5563 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",
5564 pOS2->usWinAscent, pOS2->usWinDescent,
5565 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5566 ft_face->ascender, ft_face->descender, ft_face->height,
5567 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5568 ft_face->bbox.yMax, ft_face->bbox.yMin);
5570 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5571 font->potm->otmSize = needed;
5573 #define TM font->potm->otmTextMetrics
5575 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5576 ascent = pHori->Ascender;
5577 descent = -pHori->Descender;
5578 } else {
5579 ascent = pOS2->usWinAscent;
5580 descent = pOS2->usWinDescent;
5583 if(font->yMax) {
5584 TM.tmAscent = font->yMax;
5585 TM.tmDescent = -font->yMin;
5586 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5587 } else {
5588 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5589 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5590 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5591 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5594 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5596 /* MSDN says:
5597 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5599 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5600 ((ascent + descent) -
5601 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5603 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5604 if (TM.tmAveCharWidth == 0) {
5605 TM.tmAveCharWidth = 1;
5607 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5608 TM.tmWeight = FW_REGULAR;
5609 if (font->fake_bold)
5610 TM.tmWeight = FW_BOLD;
5611 else
5613 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5615 if (pOS2->usWeightClass > FW_MEDIUM)
5616 TM.tmWeight = pOS2->usWeightClass;
5618 else if (pOS2->usWeightClass <= FW_MEDIUM)
5619 TM.tmWeight = pOS2->usWeightClass;
5621 TM.tmOverhang = 0;
5622 TM.tmDigitizedAspectX = 300;
5623 TM.tmDigitizedAspectY = 300;
5624 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5625 * symbol range to 0 - f0ff
5628 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5630 TM.tmFirstChar = 0;
5631 switch(GetACP())
5633 case 1257: /* Baltic */
5634 TM.tmLastChar = 0xf8fd;
5635 break;
5636 default:
5637 TM.tmLastChar = 0xf0ff;
5639 TM.tmBreakChar = 0x20;
5640 TM.tmDefaultChar = 0x1f;
5642 else
5644 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5645 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5647 if(pOS2->usFirstCharIndex <= 1)
5648 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5649 else if (pOS2->usFirstCharIndex > 0xff)
5650 TM.tmBreakChar = 0x20;
5651 else
5652 TM.tmBreakChar = pOS2->usFirstCharIndex;
5653 TM.tmDefaultChar = TM.tmBreakChar - 1;
5655 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5656 TM.tmUnderlined = font->underline;
5657 TM.tmStruckOut = font->strikeout;
5659 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5660 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5661 (pOS2->version == 0xFFFFU ||
5662 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5663 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5664 else
5665 TM.tmPitchAndFamily = 0;
5667 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5669 case PAN_FAMILY_SCRIPT:
5670 TM.tmPitchAndFamily |= FF_SCRIPT;
5671 break;
5673 case PAN_FAMILY_DECORATIVE:
5674 TM.tmPitchAndFamily |= FF_DECORATIVE;
5675 break;
5677 case PAN_ANY:
5678 case PAN_NO_FIT:
5679 case PAN_FAMILY_TEXT_DISPLAY:
5680 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5681 /* which is clearly not what the panose spec says. */
5682 default:
5683 if(TM.tmPitchAndFamily == 0 || /* fixed */
5684 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5685 TM.tmPitchAndFamily = FF_MODERN;
5686 else
5688 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5690 case PAN_ANY:
5691 case PAN_NO_FIT:
5692 default:
5693 TM.tmPitchAndFamily |= FF_DONTCARE;
5694 break;
5696 case PAN_SERIF_COVE:
5697 case PAN_SERIF_OBTUSE_COVE:
5698 case PAN_SERIF_SQUARE_COVE:
5699 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5700 case PAN_SERIF_SQUARE:
5701 case PAN_SERIF_THIN:
5702 case PAN_SERIF_BONE:
5703 case PAN_SERIF_EXAGGERATED:
5704 case PAN_SERIF_TRIANGLE:
5705 TM.tmPitchAndFamily |= FF_ROMAN;
5706 break;
5708 case PAN_SERIF_NORMAL_SANS:
5709 case PAN_SERIF_OBTUSE_SANS:
5710 case PAN_SERIF_PERP_SANS:
5711 case PAN_SERIF_FLARED:
5712 case PAN_SERIF_ROUNDED:
5713 TM.tmPitchAndFamily |= FF_SWISS;
5714 break;
5717 break;
5720 if(FT_IS_SCALABLE(ft_face))
5721 TM.tmPitchAndFamily |= TMPF_VECTOR;
5723 if(FT_IS_SFNT(ft_face))
5725 if (font->ntmFlags & NTM_PS_OPENTYPE)
5726 TM.tmPitchAndFamily |= TMPF_DEVICE;
5727 else
5728 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5731 TM.tmCharSet = font->charset;
5733 font->potm->otmFiller = 0;
5734 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5735 font->potm->otmfsSelection = pOS2->fsSelection;
5736 font->potm->otmfsType = pOS2->fsType;
5737 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5738 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5739 font->potm->otmItalicAngle = 0; /* POST table */
5740 font->potm->otmEMSquare = ft_face->units_per_EM;
5741 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5742 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5743 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5744 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5745 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5746 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5747 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5748 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5749 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5750 font->potm->otmMacAscent = TM.tmAscent;
5751 font->potm->otmMacDescent = -TM.tmDescent;
5752 font->potm->otmMacLineGap = font->potm->otmLineGap;
5753 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5754 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5755 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5756 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5757 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5758 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5759 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5760 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5761 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5762 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5763 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5764 if(!pPost) {
5765 font->potm->otmsUnderscoreSize = 0;
5766 font->potm->otmsUnderscorePosition = 0;
5767 } else {
5768 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5769 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5771 #undef TM
5773 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5774 cp = (char*)font->potm + sizeof(*font->potm);
5775 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5776 strcpyW((WCHAR*)cp, family_nameW);
5777 cp += lenfam;
5778 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5779 strcpyW((WCHAR*)cp, style_nameW);
5780 cp += lensty;
5781 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5782 strcpyW((WCHAR*)cp, family_nameW);
5783 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5784 strcatW((WCHAR*)cp, spaceW);
5785 strcatW((WCHAR*)cp, style_nameW);
5786 cp += lenfam + lensty;
5787 } else
5788 cp += lenfam;
5789 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5790 strcpyW((WCHAR*)cp, family_nameW);
5791 strcatW((WCHAR*)cp, spaceW);
5792 strcatW((WCHAR*)cp, style_nameW);
5793 ret = needed;
5795 if(potm && needed <= cbSize)
5797 memcpy(potm, font->potm, font->potm->otmSize);
5798 scale_outline_font_metrics(font, potm);
5801 end:
5802 HeapFree(GetProcessHeap(), 0, style_nameW);
5803 HeapFree(GetProcessHeap(), 0, family_nameW);
5805 LeaveCriticalSection( &freetype_cs );
5806 return ret;
5809 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5811 HFONTLIST *hfontlist;
5812 child->font = alloc_font();
5813 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5814 if(!child->font->ft_face)
5816 free_font(child->font);
5817 child->font = NULL;
5818 return FALSE;
5821 child->font->font_desc = font->font_desc;
5822 child->font->ntmFlags = child->face->ntmFlags;
5823 child->font->orientation = font->orientation;
5824 child->font->scale_y = font->scale_y;
5825 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5826 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5827 child->font->name = strdupW(child->face->family->FamilyName);
5828 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5829 child->font->base_font = font;
5830 list_add_head(&child_font_list, &child->font->entry);
5831 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5832 return TRUE;
5835 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5837 FT_UInt g;
5838 CHILD_FONT *child_font;
5840 if(font->base_font)
5841 font = font->base_font;
5843 *linked_font = font;
5845 if((*glyph = get_glyph_index(font, c)))
5846 return TRUE;
5848 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5850 if(!child_font->font)
5851 if(!load_child_font(font, child_font))
5852 continue;
5854 if(!child_font->font->ft_face)
5855 continue;
5856 g = get_glyph_index(child_font->font, c);
5857 if(g)
5859 *glyph = g;
5860 *linked_font = child_font->font;
5861 return TRUE;
5864 return FALSE;
5867 /*************************************************************
5868 * WineEngGetCharWidth
5871 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5872 LPINT buffer)
5874 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5875 UINT c;
5876 GLYPHMETRICS gm;
5877 FT_UInt glyph_index;
5878 GdiFont *linked_font;
5880 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5882 GDI_CheckNotLock();
5883 EnterCriticalSection( &freetype_cs );
5884 for(c = firstChar; c <= lastChar; c++) {
5885 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5886 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5887 &gm, 0, NULL, &identity);
5888 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5890 LeaveCriticalSection( &freetype_cs );
5891 return TRUE;
5894 /*************************************************************
5895 * WineEngGetCharABCWidths
5898 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5899 LPABC buffer)
5901 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5902 UINT c;
5903 GLYPHMETRICS gm;
5904 FT_UInt glyph_index;
5905 GdiFont *linked_font;
5907 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5909 if(!FT_IS_SCALABLE(font->ft_face))
5910 return FALSE;
5912 GDI_CheckNotLock();
5913 EnterCriticalSection( &freetype_cs );
5915 for(c = firstChar; c <= lastChar; c++) {
5916 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5917 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5918 &gm, 0, NULL, &identity);
5919 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5920 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5921 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5922 FONT_GM(linked_font,glyph_index)->bbx;
5924 LeaveCriticalSection( &freetype_cs );
5925 return TRUE;
5928 /*************************************************************
5929 * WineEngGetCharABCWidthsFloat
5932 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
5934 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
5935 UINT c;
5936 GLYPHMETRICS gm;
5937 FT_UInt glyph_index;
5938 GdiFont *linked_font;
5940 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
5942 GDI_CheckNotLock();
5943 EnterCriticalSection( &freetype_cs );
5945 for (c = first; c <= last; c++)
5947 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5948 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5949 &gm, 0, NULL, &identity);
5950 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
5951 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
5952 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
5953 FONT_GM(linked_font, glyph_index)->lsb -
5954 FONT_GM(linked_font, glyph_index)->bbx;
5956 LeaveCriticalSection( &freetype_cs );
5957 return TRUE;
5960 /*************************************************************
5961 * WineEngGetCharABCWidthsI
5964 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5965 LPABC buffer)
5967 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5968 UINT c;
5969 GLYPHMETRICS gm;
5970 FT_UInt glyph_index;
5971 GdiFont *linked_font;
5973 if(!FT_HAS_HORIZONTAL(font->ft_face))
5974 return FALSE;
5976 GDI_CheckNotLock();
5977 EnterCriticalSection( &freetype_cs );
5979 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5980 if (!pgi)
5981 for(c = firstChar; c < firstChar+count; c++) {
5982 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5983 &gm, 0, NULL, &identity);
5984 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5985 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5986 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5987 - FONT_GM(linked_font,c)->bbx;
5989 else
5990 for(c = 0; c < count; c++) {
5991 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5992 &gm, 0, NULL, &identity);
5993 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5994 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5995 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5996 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5999 LeaveCriticalSection( &freetype_cs );
6000 return TRUE;
6003 /*************************************************************
6004 * WineEngGetTextExtentExPoint
6007 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, 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;
6015 FT_UInt glyph_index;
6016 GdiFont *linked_font;
6018 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6019 max_ext, size);
6021 GDI_CheckNotLock();
6022 EnterCriticalSection( &freetype_cs );
6024 size->cx = 0;
6025 WineEngGetTextMetrics(font, &tm);
6026 size->cy = tm.tmHeight;
6028 for(idx = 0; idx < count; idx++) {
6029 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6030 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6031 &gm, 0, NULL, &identity);
6032 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6033 ext = size->cx;
6034 if (! pnfit || ext <= max_ext) {
6035 ++nfit;
6036 if (dxs)
6037 dxs[idx] = ext;
6041 if (pnfit)
6042 *pnfit = nfit;
6044 LeaveCriticalSection( &freetype_cs );
6045 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6046 return TRUE;
6049 /*************************************************************
6050 * WineEngGetTextExtentExPointI
6053 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6054 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6056 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6057 INT idx;
6058 INT nfit = 0, ext;
6059 GLYPHMETRICS gm;
6060 TEXTMETRICW tm;
6062 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6064 GDI_CheckNotLock();
6065 EnterCriticalSection( &freetype_cs );
6067 size->cx = 0;
6068 WineEngGetTextMetrics(font, &tm);
6069 size->cy = tm.tmHeight;
6071 for(idx = 0; idx < count; idx++) {
6072 WineEngGetGlyphOutline(font, indices[idx],
6073 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6074 &identity);
6075 size->cx += FONT_GM(font,indices[idx])->adv;
6076 ext = size->cx;
6077 if (! pnfit || ext <= max_ext) {
6078 ++nfit;
6079 if (dxs)
6080 dxs[idx] = ext;
6084 if (pnfit)
6085 *pnfit = nfit;
6087 LeaveCriticalSection( &freetype_cs );
6088 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6089 return TRUE;
6092 /*************************************************************
6093 * WineEngGetFontData
6096 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6097 DWORD cbData)
6099 FT_Face ft_face = font->ft_face;
6100 FT_ULong len;
6101 FT_Error err;
6103 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6104 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6105 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6107 if(!FT_IS_SFNT(ft_face))
6108 return GDI_ERROR;
6110 if(!buf || !cbData)
6111 len = 0;
6112 else
6113 len = cbData;
6115 if(table) { /* MS tags differ in endianness from FT ones */
6116 table = table >> 24 | table << 24 |
6117 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6120 /* make sure value of len is the value freetype says it needs */
6121 if(buf && len)
6123 FT_ULong needed = 0;
6124 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6125 if( !err && needed < len) len = needed;
6127 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6129 if(err) {
6130 TRACE("Can't find table %c%c%c%c\n",
6131 /* bytes were reversed */
6132 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6133 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6134 return GDI_ERROR;
6136 return len;
6139 /*************************************************************
6140 * WineEngGetTextFace
6143 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6145 INT n = strlenW(font->name) + 1;
6146 if(str) {
6147 lstrcpynW(str, font->name, count);
6148 return min(count, n);
6149 } else
6150 return n;
6153 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6155 if (fs) *fs = font->fs;
6156 return font->charset;
6159 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6161 GdiFont *font = dc->gdiFont, *linked_font;
6162 struct list *first_hfont;
6163 BOOL ret;
6165 GDI_CheckNotLock();
6166 EnterCriticalSection( &freetype_cs );
6167 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6168 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6169 if(font == linked_font)
6170 *new_hfont = dc->hFont;
6171 else
6173 first_hfont = list_head(&linked_font->hfontlist);
6174 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6176 LeaveCriticalSection( &freetype_cs );
6177 return ret;
6180 /* Retrieve a list of supported Unicode ranges for a given font.
6181 * Can be called with NULL gs to calculate the buffer size. Returns
6182 * the number of ranges found.
6184 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6186 DWORD num_ranges = 0;
6188 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6190 FT_UInt glyph_code;
6191 FT_ULong char_code, char_code_prev;
6193 glyph_code = 0;
6194 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6196 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6197 face->num_glyphs, glyph_code, char_code);
6199 if (!glyph_code) return 0;
6201 if (gs)
6203 gs->ranges[0].wcLow = (USHORT)char_code;
6204 gs->ranges[0].cGlyphs = 0;
6205 gs->cGlyphsSupported = 0;
6208 num_ranges = 1;
6209 while (glyph_code)
6211 if (char_code < char_code_prev)
6213 ERR("expected increasing char code from FT_Get_Next_Char\n");
6214 return 0;
6216 if (char_code - char_code_prev > 1)
6218 num_ranges++;
6219 if (gs)
6221 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6222 gs->ranges[num_ranges - 1].cGlyphs = 1;
6223 gs->cGlyphsSupported++;
6226 else if (gs)
6228 gs->ranges[num_ranges - 1].cGlyphs++;
6229 gs->cGlyphsSupported++;
6231 char_code_prev = char_code;
6232 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6235 else
6236 FIXME("encoding %u not supported\n", face->charmap->encoding);
6238 return num_ranges;
6241 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6243 DWORD size = 0;
6244 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6246 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6247 if (glyphset)
6249 glyphset->cbThis = size;
6250 glyphset->cRanges = num_ranges;
6251 glyphset->flAccel = 0;
6253 return size;
6256 /*************************************************************
6257 * FontIsLinked
6259 BOOL WineEngFontIsLinked(GdiFont *font)
6261 BOOL ret;
6262 GDI_CheckNotLock();
6263 EnterCriticalSection( &freetype_cs );
6264 ret = !list_empty(&font->child_fonts);
6265 LeaveCriticalSection( &freetype_cs );
6266 return ret;
6269 static BOOL is_hinting_enabled(void)
6271 /* Use the >= 2.2.0 function if available */
6272 if(pFT_Get_TrueType_Engine_Type)
6274 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6275 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6277 #ifdef FT_DRIVER_HAS_HINTER
6278 else
6280 FT_Module mod;
6282 /* otherwise if we've been compiled with < 2.2.0 headers
6283 use the internal macro */
6284 mod = pFT_Get_Module(library, "truetype");
6285 if(mod && FT_DRIVER_HAS_HINTER(mod))
6286 return TRUE;
6288 #endif
6290 return FALSE;
6293 static BOOL is_subpixel_rendering_enabled( void )
6295 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6296 return pFT_Library_SetLcdFilter &&
6297 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6298 #else
6299 return FALSE;
6300 #endif
6303 /*************************************************************************
6304 * GetRasterizerCaps (GDI32.@)
6306 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6308 static int hinting = -1;
6309 static int subpixel = -1;
6311 if(hinting == -1)
6313 hinting = is_hinting_enabled();
6314 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6317 if ( subpixel == -1 )
6319 subpixel = is_subpixel_rendering_enabled();
6320 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6323 lprs->nSize = sizeof(RASTERIZER_STATUS);
6324 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6325 if ( subpixel )
6326 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6327 lprs->nLanguageID = 0;
6328 return TRUE;
6331 /*************************************************************
6332 * WineEngRealizationInfo
6334 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6336 FIXME("(%p, %p): stub!\n", font, info);
6338 info->flags = 1;
6339 if(FT_IS_SCALABLE(font->ft_face))
6340 info->flags |= 2;
6342 info->cache_num = font->cache_num;
6343 info->unknown2 = -1;
6344 return TRUE;
6347 /*************************************************************************
6348 * Kerning support for TrueType fonts
6350 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6352 struct TT_kern_table
6354 USHORT version;
6355 USHORT nTables;
6358 struct TT_kern_subtable
6360 USHORT version;
6361 USHORT length;
6362 union
6364 USHORT word;
6365 struct
6367 USHORT horizontal : 1;
6368 USHORT minimum : 1;
6369 USHORT cross_stream: 1;
6370 USHORT override : 1;
6371 USHORT reserved1 : 4;
6372 USHORT format : 8;
6373 } bits;
6374 } coverage;
6377 struct TT_format0_kern_subtable
6379 USHORT nPairs;
6380 USHORT searchRange;
6381 USHORT entrySelector;
6382 USHORT rangeShift;
6385 struct TT_kern_pair
6387 USHORT left;
6388 USHORT right;
6389 short value;
6392 static DWORD parse_format0_kern_subtable(GdiFont *font,
6393 const struct TT_format0_kern_subtable *tt_f0_ks,
6394 const USHORT *glyph_to_char,
6395 KERNINGPAIR *kern_pair, DWORD cPairs)
6397 USHORT i, nPairs;
6398 const struct TT_kern_pair *tt_kern_pair;
6400 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6402 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6404 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6405 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6406 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6408 if (!kern_pair || !cPairs)
6409 return nPairs;
6411 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6413 nPairs = min(nPairs, cPairs);
6415 for (i = 0; i < nPairs; i++)
6417 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6418 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6419 /* this algorithm appears to better match what Windows does */
6420 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6421 if (kern_pair->iKernAmount < 0)
6423 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6424 kern_pair->iKernAmount -= font->ppem;
6426 else if (kern_pair->iKernAmount > 0)
6428 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6429 kern_pair->iKernAmount += font->ppem;
6431 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6433 TRACE("left %u right %u value %d\n",
6434 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6436 kern_pair++;
6438 TRACE("copied %u entries\n", nPairs);
6439 return nPairs;
6442 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6444 DWORD length;
6445 void *buf;
6446 const struct TT_kern_table *tt_kern_table;
6447 const struct TT_kern_subtable *tt_kern_subtable;
6448 USHORT i, nTables;
6449 USHORT *glyph_to_char;
6451 GDI_CheckNotLock();
6452 EnterCriticalSection( &freetype_cs );
6453 if (font->total_kern_pairs != (DWORD)-1)
6455 if (cPairs && kern_pair)
6457 cPairs = min(cPairs, font->total_kern_pairs);
6458 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6459 LeaveCriticalSection( &freetype_cs );
6460 return cPairs;
6462 LeaveCriticalSection( &freetype_cs );
6463 return font->total_kern_pairs;
6466 font->total_kern_pairs = 0;
6468 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6470 if (length == GDI_ERROR)
6472 TRACE("no kerning data in the font\n");
6473 LeaveCriticalSection( &freetype_cs );
6474 return 0;
6477 buf = HeapAlloc(GetProcessHeap(), 0, length);
6478 if (!buf)
6480 WARN("Out of memory\n");
6481 LeaveCriticalSection( &freetype_cs );
6482 return 0;
6485 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6487 /* build a glyph index to char code map */
6488 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6489 if (!glyph_to_char)
6491 WARN("Out of memory allocating a glyph index to char code map\n");
6492 HeapFree(GetProcessHeap(), 0, buf);
6493 LeaveCriticalSection( &freetype_cs );
6494 return 0;
6497 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6499 FT_UInt glyph_code;
6500 FT_ULong char_code;
6502 glyph_code = 0;
6503 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6505 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6506 font->ft_face->num_glyphs, glyph_code, char_code);
6508 while (glyph_code)
6510 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6512 /* FIXME: This doesn't match what Windows does: it does some fancy
6513 * things with duplicate glyph index to char code mappings, while
6514 * we just avoid overriding existing entries.
6516 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6517 glyph_to_char[glyph_code] = (USHORT)char_code;
6519 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6522 else
6524 ULONG n;
6526 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6527 for (n = 0; n <= 65535; n++)
6528 glyph_to_char[n] = (USHORT)n;
6531 tt_kern_table = buf;
6532 nTables = GET_BE_WORD(tt_kern_table->nTables);
6533 TRACE("version %u, nTables %u\n",
6534 GET_BE_WORD(tt_kern_table->version), nTables);
6536 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6538 for (i = 0; i < nTables; i++)
6540 struct TT_kern_subtable tt_kern_subtable_copy;
6542 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6543 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6544 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6546 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6547 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6548 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6550 /* According to the TrueType specification this is the only format
6551 * that will be properly interpreted by Windows and OS/2
6553 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6555 DWORD new_chunk, old_total = font->total_kern_pairs;
6557 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6558 glyph_to_char, NULL, 0);
6559 font->total_kern_pairs += new_chunk;
6561 if (!font->kern_pairs)
6562 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6563 font->total_kern_pairs * sizeof(*font->kern_pairs));
6564 else
6565 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6566 font->total_kern_pairs * sizeof(*font->kern_pairs));
6568 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6569 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6571 else
6572 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6574 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6577 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6578 HeapFree(GetProcessHeap(), 0, buf);
6580 if (cPairs && kern_pair)
6582 cPairs = min(cPairs, font->total_kern_pairs);
6583 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6584 LeaveCriticalSection( &freetype_cs );
6585 return cPairs;
6587 LeaveCriticalSection( &freetype_cs );
6588 return font->total_kern_pairs;
6591 #else /* HAVE_FREETYPE */
6593 /*************************************************************************/
6595 BOOL WineEngInit(void)
6597 return FALSE;
6599 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6601 return NULL;
6603 BOOL WineEngDestroyFontInstance(HFONT hfont)
6605 return FALSE;
6608 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6610 return 1;
6613 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6614 LPWORD pgi, DWORD flags)
6616 return GDI_ERROR;
6619 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6620 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6621 const MAT2* lpmat)
6623 ERR("called but we don't have FreeType\n");
6624 return GDI_ERROR;
6627 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6629 ERR("called but we don't have FreeType\n");
6630 return FALSE;
6633 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6634 OUTLINETEXTMETRICW *potm)
6636 ERR("called but we don't have FreeType\n");
6637 return 0;
6640 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6641 LPINT buffer)
6643 ERR("called but we don't have FreeType\n");
6644 return FALSE;
6647 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6648 LPABC buffer)
6650 ERR("called but we don't have FreeType\n");
6651 return FALSE;
6654 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6656 ERR("called but we don't have FreeType\n");
6657 return FALSE;
6660 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6661 LPABC buffer)
6663 ERR("called but we don't have FreeType\n");
6664 return FALSE;
6667 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6668 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6670 ERR("called but we don't have FreeType\n");
6671 return FALSE;
6674 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6675 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6677 ERR("called but we don't have FreeType\n");
6678 return FALSE;
6681 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6682 DWORD cbData)
6684 ERR("called but we don't have FreeType\n");
6685 return GDI_ERROR;
6688 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6690 ERR("called but we don't have FreeType\n");
6691 return 0;
6694 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6696 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6697 return 1;
6700 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6702 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6703 return TRUE;
6706 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6708 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6709 return NULL;
6712 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6714 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6715 return DEFAULT_CHARSET;
6718 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6720 return FALSE;
6723 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6725 FIXME("(%p, %p): stub\n", font, glyphset);
6726 return 0;
6729 BOOL WineEngFontIsLinked(GdiFont *font)
6731 return FALSE;
6734 /*************************************************************************
6735 * GetRasterizerCaps (GDI32.@)
6737 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6739 lprs->nSize = sizeof(RASTERIZER_STATUS);
6740 lprs->wFlags = 0;
6741 lprs->nLanguageID = 0;
6742 return TRUE;
6745 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6747 ERR("called but we don't have FreeType\n");
6748 return 0;
6751 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6753 ERR("called but we don't have FreeType\n");
6754 return FALSE;
6757 #endif /* HAVE_FREETYPE */